Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Filament Character Counter Laravel Package

schmeits/filament-character-counter

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:
    composer require schmeits/filament-character-counter:"^5.0"
    
  2. Publish translations (optional):
    php artisan vendor:publish --tag="filament-character-counter-translations"
    
  3. First use case: Add a character-limited TextInput to a Filament form:
    use Schmeits\FilamentCharacterCounter\Forms\Components\TextInput;
    
    TextInput::make('title')
        ->characterLimit(50)
        ->rules(['max:50']),
    

Where to Look First

  • Documentation: Focus on the README for basic usage.
  • Changelog: Review v5.0.0 for Filament v5-specific fixes (e.g., RichEditor refactor).
  • Source: Check src/Forms/Components/ for component implementations (e.g., TextInput.php, Textarea.php).

Implementation Patterns

Core Workflows

1. Basic Character Limiting

// TextInput (e.g., for a product name)
TextInput::make('name')
    ->characterLimit(30)
    ->maxLength(30) // Hard limit + visual counter
    ->rules(['max:30']);

// Textarea (e.g., for a blog post excerpt)
Textarea::make('excerpt')
    ->characterLimit(160)
    ->rows(3);

2. RichEditor Integration

use Filament\Forms\Components\RichEditor;

RichEditor::make('content')
    ->characterLimit(1000)
    ->columnSpanFull()
    ->disableToolbarButtons(['bold', 'italic']); // Optional: Customize toolbar

3. Conditional Counters

Textarea::make('bio')
    ->characterLimit(255)
    ->showCharacterCounter(fn (Get $get) => $get('is_public'))
    ->showInsideControl(true); // Place counter inside the field

4. Dynamic Limits

TextInput::make('slug')
    ->characterLimit(fn (Get $get) => $get('is_short') ? 30 : 50)
    ->dehydrateStateUsing(fn (string $state) => Str::slug($state));

Integration Tips

  • Form-Level Validation: Combine with Filament’s built-in validation:
    $form->afterStateUpdated(function (Form $form) {
        if ($form->getComponent('title')->getStateLength() > 50) {
            $form->addError('title', 'Exceeded character limit.');
        }
    });
    
  • Livewire Hooks: Extend functionality with Livewire:
    protected function getListeners(): array
    {
        return [
            'characterCountUpdated' => 'updateCharacterCount',
        ];
    }
    
  • Custom Styling: Override the counter’s appearance via CSS:
    .filament-character-counter {
        color: #ff4444;
        font-size: 0.875rem;
    }
    

Gotchas and Tips

Pitfalls

  1. characterLimit vs. maxLength:

    • characterLimit() is a soft limit (visual counter only).
    • maxLength() enforces a hard limit (HTML maxlength + validation).
    • Fix: Use both for strict enforcement:
      TextInput::make('tagline')
          ->characterLimit(20)
          ->maxLength(20)
          ->rules(['max:20']);
      
  2. RichEditor Quirks:

    • Livewire v4 (Filament v5): The counter may lag slightly due to DOM updates. Use Livewire.hook('commit') for sync:
      Livewire.hook('commit', () => {
          updateCharacterCount();
      });
      
    • Tip: Add a debounce to the RichEditor’s character count update:
      ->extraAttributes(['data-debounce' => '300'])
      
  3. Translation Keys:

    • Default keys: character_seperator (e.g., " / ") and character_label (e.g., "characters").
    • Fix: Publish translations if using custom labels:
      config(['filament-character-counter.character_label' => 'zeichen']);
      
  4. SPA/Alpine.js Issues:

    • If counters stutter in SPAs, ensure Alpine.js is loaded after the component:
      @push('scripts')
          <script src="{{ asset('js/alpine.js') }}" defer></script>
      @endpush
      

Debugging

  • Counter Not Updating?:

    • Check for JavaScript errors in the browser console.
    • Verify Alpine.js is initialized (look for Alpine.start()).
    • Debug: Temporarily disable other Alpine components to isolate the issue.
  • RichEditor Counting Incorrectly:

    • Inspect the DOM to ensure the counter is targeting the correct element:
      console.log(document.querySelector('.fi-fo-rich-editor-wrapper').textContent.length);
      
    • Fix: Override the RichEditor view if needed (extend rich-editor.blade.php).

Extension Points

  1. Custom Counter Logic:

    • Extend the HasCharacterLimit trait to add logic (e.g., word limits):
      use Schmeits\FilamentCharacterCounter\Concerns\HasCharacterLimit;
      
      class CustomTextarea extends Textarea
      {
          use HasCharacterLimit;
      
          public function wordLimit(int $limit): static
          {
              $this->extraAttributes(['data-word-limit' => $limit]);
              return $this;
          }
      }
      
  2. Localization:

    • Add custom translations by publishing the config and extending the character_label:
      config([
          'filament-character-counter' => [
              'character_label' => trans('custom.characters'),
          ],
      ]);
      
  3. Testing:

    • Mock the counter in PHPUnit:
      $field = TextInput::make('test')
          ->characterLimit(10);
      
      $field->fill('test');
      $this->assertEquals(4, $field->getStateLength());
      
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codraw/entity-migrator
codraw/doctrine-extra
codraw/aws-tool-kit
codraw/validator
codraw/workflow
codraw/open-api
codraw/cron-job
codraw/process
codraw/log
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony