martin-ro/filament-charcount-field
A Filament form field that adds a live character counter to text inputs and textareas, helping users track remaining characters against a configured limit and giving clearer, constraint-aware form input.
The package provides Filament form fields that display a live character counter alongside the input — useful anywhere you show a maxLength on a TextInput or Textarea and want the user to see how many characters remain.
Install
composer require martin-ro/filament-charcount-field
Filament will auto-discover the service provider. No migrations, no config to publish (if a config/filament-charcount-field.php exists in the repo, publish it with php artisan vendor:publish --tag="filament-charcount-field-config").
Where to look first
README.md — the field class names and options are the whole public API; read this before anything else.src/ — confirm the namespace (MartinRo\FilamentCharCountField\...) and the exact class names (typically CharCountTextInput / CharCountTextarea, or possibly a charCount() macro on the standard fields). Match your usage to what is actually exported.composer.json before adopting it.First use case
In any Resource form, swap the standard field for the char-count variant:
use MartinRo\FilamentCharCountField\CharCountTextarea; // verify exact name
CharCountTextarea::make('bio')
->maxLength(280)
->rows(4),
You get the same fluent API as a normal Textarea, plus a counter that updates as the user types.
Treat it as a drop-in replacement. These fields are thin wrappers around TextInput/Textarea, so ->required(), ->rules(), ->prefix(), ->reactive(), ->live(), ->afterStateUpdated() all behave normally. Migrate one field at a time; you don't need to touch unrelated fields.
Keep maxLength() as the single source of truth. Set the limit in PHP and let the counter read from it, rather than hardcoding a number in the UI copy and another in validation:
CharCountTextInput::make('slug')
->maxLength(60)
->helperText('Keep it short and memorable.'),
Use it for user-facing copy fields, not IDs. The counter is only meaningful where humans are typing and a limit is visible — headlines, meta descriptions, SEO titles, tweets, SMS bodies. Skip it for machine-generated or internally capped columns.
Reusable snippets. If you have several forms with the same constrained field (e.g. meta_title capped at 60 across many Resources), extract a small static helper or a custom field class that returns the configured field, so the max length and label stay consistent everywhere.
Pair with live validation for length-sensitive UX. If the field matters (SEO preview, character-budget UI), combine ->live() with a ->rules(['max:60']) and a sibling field or placeholder showing the truncated preview. The counter handles the "how many left" feedback; the live rule handles correctness.
Use inside Sections/Repeaters as normal. Builders, Repeaters, and nested Groups don't change anything — configure the field the same way you would a native one.
src/. Small packages like this often rename classes between tags (CharCountTextarea vs CharCountTextareaField). Grep the source or README rather than guessing; a wrong class name produces a confusing "class does not exist" during form render, not at compile time.php artisan filament:assets) and you aren't on a stale manifest. In a custom Vite theme, ensure the package's JS is actually registered, not just PHP-loaded.maxLength mismatch. If you set the HTML limit via maxLength() but validate with a different rule (max:280 in a Form Request or ->rules()), the counter and the error message will disagree. Keep them equal, or validate only through maxLength().composer.json and smoke-test after every Filament upgrade — this package has few dependents, so breakage won't be loudly reported.TextInput::make() by accident). Then check the browser console for a 404 on the package's JS asset, and confirm maxLength() is actually set — many implementations only show a counter when a limit exists.aria-describedby/aria-live, that's typically an extension point (override getView() or the Blade view) rather than a config option — plan for a small custom field if this matters.How can I help you explore Laravel packages today?