Weave 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 Badgeable Column Laravel Package

awcodes/filament-badgeable-column

Filament Badgeable Column lets you show additional context as badges alongside table column values. Add prefix or suffix badges with dynamic labels and colors, making statuses and metadata easier to scan in Filament tables.

View on GitHub
Deep Wiki
Context7

Getting Started

Three steps, in this order, and you have a working badge column:

  1. Install the matching major. The version line is tied to Filament, not to the package's own features:

    Package Filament
    1.x 2.x
    2.x 3.x
    3.x 4.x
    4.x 4.x & 5.x

    On Filament 5 the safe target is ^4.2 (the 4.x line was deliberately consolidated to serve both 4 and 5). composer require awcodes/filament-badgeable-column and then check composer show rather than assuming.

  2. Wire up the theme CSS. This is the step people skip and then file bugs about. If you use a custom Filament theme (or the standalone Tables package with its own CSS), the package's Blade views must be scanned by Tailwind:

    @source '../../../../vendor/awcodes/filament-badgeable-column/resources/**/*.blade.php';
    

    No @source line means badges render with no padding, colour or rounding — the markup is there, the classes just were never compiled.

  3. Replace one TextColumn you already have. Start with the highest-signal column in your biggest resource — usually a status or name column:

    use Awcodes\BadgeableColumn\Components\Badge;
    use Awcodes\BadgeableColumn\Components\BadgeableColumn;
    
    BadgeableColumn::make('name')
        ->prefixBadges([
            Badge::make('status')
                ->label(fn (Model $record) => $record->status)
                ->color(fn (Model $record) => match ($record->status) {
                    'active' => 'success',
                    'inactive' => 'danger',
                    default => 'warning',
                }),
        ])
        ->searchable()
        ->sortable(),
    

Where to look first: BadgeableColumn extends Filament's TextColumn, so nearly every method you already know (searchable(), sortable(), formatStateUsing(), weight()) still works — read the README's Usage / Badge Shape / Separator / Font sections, then keep CHANGELOG.md open, because most breaking changes in this package are Filament compatibility fixes rather than feature changes.

Implementation Patterns

Prefix vs suffix. prefixBadges() puts badges between the row label and the column state; suffixBadges() puts them after. Use prefix for identity/status metadata ("this is an Active customer") and suffix for derived or secondary warnings ("Hot — low stock"). Mixing both on one column is fine but reads poorly past two or three badges.

Closures for dynamic badge sets. When the number of badges varies per record, return the array from a closure — the canonical case is a BelongsToMany:

BadgeableColumn::make('title')
    ->suffixBadges(fn ($record) => $record->topics->map(
        fn ($topic) => Badge::make($topic->name)->color($topic->color)
    ))
    ->searchable()
    ->sortable(),

Per-badge label(), color(), textColor() and visible() all accept closures receiving the record, so you can keep the badge list static and push the variation into the badge itself. Prefer that when the count is stable — it keeps the closure surface small and makes the column declaration readable.

Reuse across the app. Extract badge factories into small helper methods or a dedicated class (StatusBadge::for($record)) and call them from every resource. Badge columns multiply quickly; the third copy of a match on status is where colour drift starts.

Infolists. The description explicitly covers infolist entries, not only table columns — so the same BadgeableColumn can be dropped into a ViewRecord schema to keep the detail page consistent with the list page. Build the badge set once and share it between the two.

Presentation knobs. asPills() on the column sets badge shape; separator() changes the — between the state text and the badges; fontFamily(), weight() and size() exist on both the column (styling the column's own text) and the Badge (styling the badge). A size(Size::Small) badge beside a normal-weight label is the layout that survives dense tables best.

Gotchas and Tips

  • Pin the patch version on Filament 4.15+/5.10+. TextColumn::getPrefix() / getSuffix() gained optional $state and $relatedRecord parameters; the package's HasBadges overrides were incompatible and produced a fatal error on load. Fixed in 3.2.1 / the corresponding 4.x release. If a Filament upgrade white-screens a table, check this package first.
  • Upgrading Filament 5.7+? formatStateUsing passthrough was broken and restored in 3.2.0 / 4.1.0 — columns rendered blank or ignored formatting. Same lesson: upgrade package and Filament together, never one alone.
  • Tailwind @source is not optional. Unstyled badges after install are almost always this. Rebuild assets (npm run build) and hard-refresh; also confirm the relative path depth matches your theme file's location.
  • N+1 on relationship badges. $record->topics inside the closure lazy-loads per row. Eager load via ->modifyQueryUsing(fn ($query) => $query->with('topics')) on the table, or the badge column will quietly make a 30-row table issue 30 queries.
  • Badge::make() takes a name that behaves like a key — duplicates are deduped, and the name is the fallback label. Give each badge a distinct name (e.g. 'status', 'hot') even when you override label().
  • Watch row height. Badges don't collapse; a record with twelve tags turns the row into a block. Cap the set (slice the collection, or ->visible() on anything past N) and rely on asPills()/size(Size::Small) for density. Long badge lists historically got wrapping support — worth checking the current API before hand-rolling a wrap div.
  • Null states. Rendering with an empty state has been patched more than once; guard your closures ($record->status ?? 'unknown') rather than trusting the package to absorb nulls.
  • Column-level vs badge-level styling is the most common confusion. ->weight(FontWeight::Bold) on the column bolds the state text; on the Badge it bolds the badge. The README calls this out explicitly and it's still the number one "why won't it style" question.
  • Extension point: subclass BadgeableColumn (or the trait it uses) if you need house-standard defaults — e.g. always asPills() and always Size::Small — instead of repeating the chain across forty resources.
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.
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc
animalyoung/laravel-influxdb
onix-solutions/sms-telera
lonely-lights/prosetta
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log