drafolin/filament-collapse
drafolin/filament-collapse is a Filament plugin for building collapsible form sections. Wrap fields in expandable panels to keep long forms tidy, reduce scrolling, and let users focus on the inputs that matter. Simple to install and configure in Filament resources and forms.
Install
composer require drafolin/filament-collapse
There is no service provider config to publish in most setups — the package ships a Filament form component you reference directly from your form schema. Check composer.json of the package for the filament/filament constraint before installing (see Gotchas).
Where to look first
drafolin/filament-collapse) — it documents the single component class and its fluent API. With 12 stars and a single maintainer, treat the README and src/ as the canonical docs; there is no docsite, no ecosystem, no StackOverflow corpus.vendor/drafolin/filament-collapse/src/ — read the component class itself. This is a small package; the source is the fastest way to confirm the exact namespace, method names, and how state is merged.Filament\Forms\Components\ToggleButtons::grouped(), in Filament's own source — the package deliberately mirrors that grouping UX, so understanding grouped() tells you what the package is trying to reproduce for arbitrary fields.First use case
The package is aimed at the "many small fields, one visual unit" problem: a country-code select plus a phone-number input, a currency selector plus an amount, or a prefix plus an identifier. Instead of rendering each field on its own row inside the form grid, you wrap them in the collapse component so they render grouped/condensed — the same feel as ToggleButtons->grouped(), but for fields that aren't toggle buttons. The quickest sanity check is a throwaway form on an existing resource: wrap two related fields, verify values still hydrate and validate correctly in create and edit.
Grouping sibling fields in a form schema
The core pattern is to use the component as a wrapper/layout element inside form(Schema $schema), passing the child fields in. Treat it like a Group or Fieldset for layout purposes — it controls presentation, not the field names or validation rules. Keep the fields' own ->required(), ->rules(), and ->reactive() declarations on the children, not on the wrapper.
use Drafolin\FilamentCollapse\...; // confirm from src/
Select::make('country_code')->options(...)->required(),
TextInput::make('phone')->tel()->required(),
placed inside the collapse component so they render as one grouped block rather than two stacked inputs.
Pairing with reactive/live forms
Because the visible behavior mimics grouped(), the most valuable day-to-day use is compact conditional UI: wrap a set of fields that belong together logically (address line 1 + 2, or a metric + unit selector) and drive their visibility off a single toggle elsewhere in the form. Keep the ->live()/->reactive() on the driver field, not the collapsed wrapper, so the wrapper doesn't add unnecessary update round-trips.
Inside resources, relation managers, and settings pages
The component is a schema element, so it drops into any Schema container: resource create/edit forms, RelationManager forms, and Settings page schemas alike. The pattern to standardize on is a small private method on the resource (e.g. phoneFieldGroup()) returning the pre-configured collapse block, so the same grouped layout is reused across resource forms without copy-paste drift.
Compact "segmented" UX without ToggleButtons
Where you would otherwise reach for a ToggleButtons or Radio field with a small option set, the collapse grouping lets you build a custom compact control out of plain fields. Use this sparingly — you get the look of grouped() without the accessibility/keyboard semantics that the native control brings, so reserve it for genuinely low-stakes inputs.
Layout discipline in the grid
Because it's a wrapper, its column span matters more than the children's. Set ->columnSpan(...) / ->columnSpanFull() on the collapse wrapper and let the children fill it, rather than fighting the parent grid from inside. Test in a two-column resource form, since that's the common realistic layout.
filament/filament constraint and test the component against your app's version before adopting it — do not assume the README matches your install.dehydrated() behavior. If country_code and phone need to combine into one column, do that with a ->dehydrateStateUsing() on the field or a form mutateFormDataBeforeSave, not by hoping the wrapper does it.app/Filament/Components/ and own it if you depend on it in production. MIT means this is a legitimate option and often the right one for something this small.components([...])), not a field expecting ->options(). Second, check column spans — "not grouped" is frequently just "wrapped onto two grid rows."->live(debounce: ...) on a sibling.publish views if the package supports it, otherwise view() on your subclass). Don't wait on upstream for a view tweak.assertFormFieldExists) and that validation still runs on each child — cheap insurance that a Filament upgrade didn't silently change how the wrapper mounts children.Grid::make(2) or a Group with columns() gets you there with zero third-party risk. Reach for this package specifically when you want the condensed grouped aesthetic that plain layout can't produce.How can I help you explore Laravel packages today?