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

Laravel Filament Components Laravel Package

ralphjsmit/laravel-filament-components

A set of reusable, ready-made components for Filament by Ralph Jsmit, including form fields, table columns, and UI widgets that speed up building admin panels in Laravel. Drop-in Blade and PHP components keep your Filament resources clean and consistent.

View on GitHub
Deep Wiki
Context7

Getting Started

Prerequisites. You must already be on Filament (panels) — this package is a pure presentational layer on top of it. Before installing, check the constraint the package declares against your pins:

composer show ralphjsmit/laravel-filament-components --all | grep -A5 requires

Look specifically at the filament/filament, php, and laravel/framework constraints. A Filament major mismatch is the single most common way this adoption fails, and it fails at render time with confusing "component not found" or markup errors rather than at install time.

Install.

composer require ralphjsmit/laravel-filament-components

Laravel auto-discovery registers the service provider; there is no migration, no config to publish to get started, and nothing to add to a panel provider unless the README says otherwise.

Where to look first — the vendor views, not the README. The authoritative component inventory is the source itself:

ls vendor/ralphjsmit/laravel-filament-components/resources/views/components/

Each file is one Blade component, and each file is its own documentation: props are the @props([...]) array at the top, variants are the conditional class logic, and slots are {{ $slot }}. Read the three components you actually intend to use, ignore the rest of the catalog. Do not adopt the whole set on day one.

Resolve the asset question before writing any markup. This is a five-minute check that determines whether integration is an afternoon or a week:

ls vendor/ralphjsmit/laravel-filament-components/dist 2>/dev/null
ls vendor/ralphjsmit/laravel-filament-components/resources/css 2>/dev/null
  • If there's a precompiled CSS file registered by the provider, you're done — components render correctly with your existing Filament theme.
  • If not, the components rely on Tailwind classes that your compiled Filament theme does not currently emit. You will need a custom Filament theme (php artisan make:filament-theme) and a content entry pointing at the vendor views (see Gotchas).

First use case: a gallery page, not a feature. Before touching a real resource, build a throwaway Filament page that renders each candidate component in every variant and in both light and dark mode. Ten minutes of work, and it becomes your permanent canary for Filament upgrades:

// app/Filament/Pages/ComponentGallery.php
class ComponentGallery extends Page
{
    protected static string $view = 'filament.pages.component-gallery';

    public static function canAccess(): bool
    {
        return app()->isLocal() || auth()->user()?->isAdmin();
    }
}
{{-- resources/views/filament/pages/component-gallery.blade.php --}}
<x-filament-panels::page>
    <x-filament-components::card>
        <x-slot name="header">Default</x-slot>
        Gallery content
    </x-filament-components::card>
</x-filament-panels::page>

Note the nesting: the package component goes inside <x-filament-panels::page>, never replaces it. The panel wrapper owns the page chrome, breadcrumbs, and heading.

Publish views only when you need to override something. Publishing the whole set up front creates a fork you now maintain. Publish lazily, one component at a time, once you've hit a case the props don't cover.

Implementation Patterns

Pattern 1 — Custom Filament pages

The highest-value, lowest-risk integration point. Custom pages are just Blade views, so components drop in with zero ceremony:

class OpsDashboard extends Page
{
    protected static string $view = 'filament.pages.ops-dashboard';

    protected function getViewData(): array
    {
        return ['queues' => QueueHealth::snapshot()];
    }
}

Keep the data assembly in getViewData() (or a dedicated action/service) and keep the Blade view purely presentational. The moment you find yourself doing @php arithmetic in the view, the component set has stopped helping.

Pattern 2 — Render hooks

For cross-cutting UI that belongs on every resource page (a beta banner, an environment ribbon, a support link), use Filament render hooks rather than editing forty resource views:

use Filament\View\PanelsRenderHook;

$panel->renderHook(
    PanelsRenderHook::PAGE_HEADER_ACTIONS_BEFORE,
    fn (): string => Blade::render(
        '<x-filament-components::alert type="warning" :dismissible="false">
            Staging environment — changes affect shared data.
        </x-filament-components::alert>'
    ),
);

Prefer a real view file over an inline Blade::render string once the markup exceeds a couple of lines — inline strings get no syntax highlighting, no editor completion, and no view:cache benefit.

Pattern 3 — Inside form and schema layouts

Filament's schema components render arbitrary views, which is how package components get into form layout without writing a custom field class:

use Filament\Forms\Components\Placeholder;
use Filament\Forms\Components\ViewField;

->schema([
    Placeholder::make('notice')
        ->hiddenLabel()
        ->content(view('filament.forms.partials.deprecation-notice')),

    ViewField::make('preview')
        ->view('filament.forms.partials.asset-preview'),
])

Rule of thumb: use the package for the chrome around a field (callouts, section wrappers, empty states), and keep the actual input controls as native Filament fields. Native fields carry validation, state binding, and accessibility wiring you do not want to reimplement.

Pattern 4 — Table columns that need real markup

TextColumn supports ->html(); combine it with Blade::render to emit a package component per row:

use Illuminate\Support\Facades\Blade;

TextColumn::make('status')
    ->html()
    ->formatStateUsing(fn (string $state): string => Blade::render(
        '<x-filament-components::badge :color="$color">{{ $label }}</x-filament-components::badge>',
        [
            'color' => match ($state) {
                'paid'    => 'success',
                'overdue' => 'danger',
                default   => 'gray',
            },
            'label' => str($state)->headline(),
        ],
    )),

Two constraints: Blade::render cannot see the column's $record or $get closures, so pass primitives in the data array; and rendering a Blade component per row per column is measurable on large tables — test with realistic row counts (50+), not three fixtures.

Pattern 5 — Infolists and read-only detail views

Detail pages are where these components earn their keep, because read-only views are almost entirely layout:

ViewEntry::make('summary')
    ->view('filament.infolists.order-summary'),

Keep the Blade partial dumb — receive an array, render it. If you start passing models into the partial and calling relationships, you're rebuilding resource pages by hand.

Pattern 6 — Widgets

Widgets are Blade views with a PHP class attached, so the same rules apply:

class OnboardingChecklist extends Widget
{
    protected static string $view = 'filament.widgets.onboarding-checklist';

    protected int|string|array $columnSpan = 'full';

    protected function getViewData(): array
    {
        return ['steps' => Onboarding::stepsFor(auth()->user())];
    }
}

Because widgets re-render on polling, be careful with Alpine state inside package components — anything with x-data needs a stable wire:key when rendered in a loop, or live updates will reset it.

Pattern 7 — Modals, notifications, and action content

->modalContent(view(...)) and notification bodies both accept views. This is a clean place to use components for confirmation dialogs and empty-state messaging:

Action::make('archive')
    ->requiresConfirmation()
    ->modalContent(view('filament.modals.archive-warning'))
    ->action(fn (Order $record) => $record->archive());

Pattern 8 — Wrap, don't sprinkle

Once you've adopted more than three components, add a thin project layer so your app owns the API surface:

{{-- resources/views/components/app/status-badge.blade.php --}}
<x-filament-components::badge :color="$color" {{ $attributes->class(['text-xs']) }}>
    {{ $slot }}
</x-filament-components::badge>

Two wins: a single place to swap in a hand-rolled replacement if the package stalls, and your views stop depending on the vendor namespace directly. This is the cheapest possible version of the fork contingency — it turns a potential multi-day vendoring job into a handful of file edits.

Pattern 9 — Gallery as upgrade canary

Keep the gallery page from Getting Started in staging permanently, gated to admins. Every time you bump Filament or the package, open it first. Visual regressions surface there in seconds instead of surfacing as a broken checkout screen three days after deploy. Screenshot it before and after upgrades if you have any visual diff tooling.

Gotchas and Tips

Tailwind purging is the number one failure mode. If the components rely on classes not in your compiled theme, everything renders in development (if you're using Vite HMR against source) and looks structurally broken in production, or vice versa — either way the discrepancy wastes an afternoon. Fix in your Filament theme config:

// tailwind.config.js (or the theme's config)
content: [
    './resources/**/*.blade.php',
    './app/Filament/**/*.php',
    './vendor/ralphjsmit/laravel-filament-components/resources/views/**/*.blade.php',
],

Then rebuild (npm run build) and re-check. Confirm the published theme is actually wired to the panel via ->viteTheme('resources/css/filament/admin/theme.css') — a theme that exists but isn't registered produces exactly the same symptom.

Check dark mode explicitly. Your gallery pass should toggle dark mode on every variant. Packages built against Filament's design system usually inherit this correctly, but a single hardcoded bg-white in an override will only show up at night, in front of a stakeholder.

Always use the full namespace prefix. <x-filament-components::card> will not collide with your own <x-card>. The un-prefixed form will, silently, and the resulting bug looks like "my card lost its styles" rather than "I rendered the wrong component."

Blade::render returns a plain string. Anything consuming it must be in HTML mode: ->html() on columns and entries, HtmlString for anything type-hinted. Forgetting this yields escaped tags rendered literally in the cell.

Class merging, not class appending. Pass overrides via the class attribute and verify the component uses $attributes->class([...]) (merge) rather than string concatenation (duplicate Tailwind classes, where the winner depends on stylesheet order). If overrides don't take, read the component source — it's one file, and the answer is in the first ten lines.

Clear caches when you publish or edit overrides. php artisan view:clear after any vendor-publish. Published views shadow the originals, so a published-and-forgotten component will silently ignore a package upgrade.

Beware the "upgrade does nothing" trap. Published views do not receive upstream fixes. Keep a list of everything you've published; that list is your upgrade checklist.

Don't put business logic in components. They are presentational. If a component needs a query, a policy check, or a formatted domain value, assemble that in getViewData(), a view model, or a small presenter — not in the Blade file, and definitely not by adding methods to a vendored class.

Filament major upgrades are a manual gate. Add a CI step that fails loudly on Filament major bumps:

composer update --dry-run filament/filament | grep -q "v4" && exit 1

The package tracks Filament, but it tracks it with a delay and it is a single-maintainer project. Your upgrade runbook should be: bump Filament → open the gallery → screenshot → only then merge.

Pin the version and mirror it if builds matter. composer.lock is enough for reproducibility, but if your deploy pipeline cannot tolerate a Packagist outage on a single-author package, mirror it into a private Satis repository. Cheap insurance, one afternoon.

Measure the payload before it reaches customers. Every registered component ships CSS (and potentially JS) to admin clients. Fine for internal tools; before this touches a customer-visible surface, check the compiled asset size delta.

Accessibility is unverified by default. Community component packages rarely ship an a11y contract. Do a keyboard pass on anything interactive — focus rings, tab order, aria-* on toggles — and prefer native Filament fields for anything a user must operate, reserving these components for display and layout.

Have the exit ramp written down before you need it. Views are publishable and the license is MIT, so the worst case is vendoring the handful of components you actually use into app/Filament/Components at roughly 1–2 engineer-days each. Do this the moment the package goes quiet on a Filament major you need — don't wait for it to break in production. The Pattern 8 wrapper layer is what makes that swap a sed-like edit instead of a codebase-wide search.

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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource