Filter.Dock

The editor as a rail beside the list, applying live; a drawer on mobile.

Press Filters: the rail opens beside the rows and stays there while you narrow, read, and narrow again. A panel that covers the answer has to be dismissed before each read; a rail does not.

5 results
  • Welcome aboard
  • Your invoice is ready
  • Password changed
  • Weekly digest
  • A new device signed in
const [open, setOpen] = useState(false);
 
<Filter.Root
	mode="live"
	definitions={definitions}
	values={values}
	onValuesChange={setValues}
	open={open}
	onOpenChange={setOpen}
	panelRenderedElsewhere
/>
 
<div className="flex gap-4">
	<Table className="flex-1" />
	<Filter.Dock
		open={open}
		onOpenChange={setOpen}
		definitions={definitions}
		values={values}
		onValuesChange={setValues}
	/>
</div>;

panelRenderedElsewhere tells the bar to draw no editor of its own: its button becomes a pressed/unpressed toggle for the rail, so the two never both draw the fields. Under 768px the dock is the live Filter.Sheet drawer instead — a rail would leave no room for the rows it filters.

API

PropTypeDefault
definitionsreadonly FilterDefinition[]requiredThe filters to edit, in the order they are rendered.
onOpenChange(open: boolean) => voidrequiredCalled by the rail's own close button (and by the drawer on mobile).
onValuesChange(values: Readonly<Record<string, FilterValue>>) => voidrequiredCalled as the filters change: at once for a tap, after a 300 ms pause for typing. Safe to use as a fetch key.
openbooleanrequiredWhether the rail shows. Controlled; the bar's trigger usually toggles it.
valuesReadonly<Record<string, FilterValue>>requiredThe applied record. Changes made elsewhere (a removed chip) flow back in.
labelsPartial<FilterLabels>—Overrides for the strings the rail shows, merged over the surrounding filter root's. The rail usually sits outside the bar that declared the copy, so pass the same labels to both.
localestring—BCP 47 tag used to format the numbers, money and dates; inherited when omitted.
exitExit—Inside a <Presence>: plays this child's way out before it unmounts.

Plus every <aside> prop. Source: filter/components/filter-dock.tsx.

The rail is sticky so it follows a page-scrolled list down; in a full-height layout whose table scrolls itself, pass className="static h-full max-h-none". It usually sits outside the bar in the tree, so give it the same labels and locale — or wrap both in one Filter.Provider.