Search for a command to run...
Collapsible animated container for a horizontal row of `FilterChip`s. Spring-based height animation reads as a real drawer; the inner row scrolls horizontally on touch when chips overflow. Comes with an opinionated `FilterBarTrigger` (bars-filter icon button) whose `active` state picks up the blue `info` tint when any filter is on.
FilterBar is a compound primitive: a Root provides open-state context, an opinionated Trigger (icon button with BarsFilterIcon) toggles it, and Content is the collapsible row. Trigger and Content can be siblings — they don't need to be wrapped together — so place the trigger inside a page header and the content directly below.
FilterBarThe state container. Pass defaultOpen for an uncontrolled initial state, or wire open + onOpenChange for controlled mode.
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | — | Controlled open state. |
defaultOpen | boolean | false | Uncontrolled initial state. |
onOpenChange | (open: boolean) => void | — | Fires when the open state changes. |
FilterBarTriggerOpinionated icon button — size-9 rounded-full ghost chip with BarsFilterIcon. Toggles FilterBar's open state on click; styling is baked in so the trigger looks identical across the app.
| Prop | Type | Default | Description |
|---|---|---|---|
active | boolean | false | When true, the trigger picks up the blue info-tinted surface — users can see filters are on even when the bar is collapsed. |
icon | ReactNode | <BarsFilterIcon /> | Override the default glyph. Sizing is handled here — pass a bare icon, no className needed. |
A data-state="open" \| "closed" attribute and data-active (when active) are forwarded for downstream styling if needed.
FilterBarContentThe collapsible row. Height animates between 0 and auto via a spring; content cross-fades during the transition.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | Applied to the outer animated container (use for margins, borders). |
contentClassName | string | — | Applied to the inner horizontal scroll row (default: flex gap-2 px-4 py-3). |
The inner row uses overflow-x-auto touch-pan-x with a hidden scrollbar so a long list of chips can scroll horizontally on touch without a visible track.
useFilterBarRead the current { open, onOpenChange } from the context. Useful when a sibling element needs to render different content based on state (e.g. a "Filters on" caption next to the trigger).
Reach for FilterBar whenever a list / table page exposes filters that don't fit in the
header. The collapsing row keeps the table chrome quiet by default and unfolds only on demand.
Pass active={anyFilterApplied} to FilterBarTrigger — the blue info tint is the only signal
the user has that filters are on when the bar is collapsed.
Mix toggle chips (onClick + active) with picker chips (<PopoverTrigger asChild> +
<FilterChip> + <PopoverContent>) freely — both work inside the same bar.
Persist the bar's open state to localStorage (or a URL flag) when the user toggles it. The
bar should remember their preference between sessions for power users.
Pre-open the bar on pages where most users won't filter. The collapsed state is the quieter
visual; only defaultOpen when filtering is the primary action.
Stuff 10+ chips in one bar. Past that the horizontal scroll becomes the only way to discover
filters — split into grouped sections or move advanced filters into a Sheet.