Filter toolbar

Keep collection filters close and easy to reset.

pnpm dlx shadcn@latest add @uiarc/filter-toolbar
Live · keyboard ready
  • Faceted filtering above tables and lists, with removable chips.
  • Adding filters through a two step field then value menu.
  • Views that pair with sortable-data-table and pagination for a full list page.
  • Use chip-group for a fixed set of toggles.
  • Use search-field for free text search.
  • Use multi-select when one field takes several values in a form.

Installation

Add Filter toolbar with the shadcn CLI, or copy the source by hand.

pnpm dlx shadcn@latest add @uiarc/filter-toolbar

Adds the component and its local dependencies, and installs motion, lucide-react. First time? Add the @uiarc registry to components.json, or use the full URL:

example.tsx
import { useState } from "react";import { FilterToolbar, type FilterChip } from "@/registry/components/filter-toolbar/filter-toolbar"; const fields = [  { id: "status", label: "Status", options: ["Open", "Closed"] },  { id: "owner", label: "Owner", options: ["Maya", "Leo"] },]; export function IssueFilters() {  const [filters, setFilters] = useState<FilterChip[]>([]);  return (    <FilterToolbar      filters={filters}      onRemove={id => setFilters(f => f.filter(x => x.id !== id))}      onClearAll={() => setFilters([])}      addFilter={{ fields, onAdd: chip => setFilters(f => [...f.filter(x => x.id !== chip.id), chip]) }}    />  );}

API reference

2 parts. The first is the root.

FilterToolbar

A row of removable filter chips with Clear all and an optional Add filter menu.

PropTypeDefaultDescription
filtersRequired{ id: string; label: string; value?: string }[]–Applied filters, shown as chips.
onRemoveRequired(id: string) => void–Called when a chip's remove button is pressed.
onClearAll() => void–Called by Clear all, which appears while any filter is applied.
addFilter{ fields: FilterField[]; onAdd: (filter: FilterChip, field: FilterField) => void; label?: string; align?: "start" | "end" }–Adds an Add filter trigger that opens a two step field and value menu.
childrenReactNode–Extra actions next to the Add filter trigger.
labelstring"Active filters"Accessible name for the toolbar group.

FilterMenu

The Add filter trigger and its two step menu, usable on its own.

PropTypeDefaultDescription
fieldsRequired{ id: string; label: string; icon?: ReactNode; options: (string | { value: string; label?: string; hint?: string | number; icon?: ReactNode })[] }[]–Filterable fields and their values.
onSelectRequired(filter: FilterChip, field: FilterField) => void–Receives a chip whose id is the field id, so a second pick for a field replaces the first.
activeFilterChip[][]Applied filters, used to mark current values.
labelstring"Add filter"Trigger text.
align"start" | "end""end"Trigger edge the panel lines up with. Flips when there is no room.
ArrowDownorArrowUp
On the trigger, opens the menu at the first or last item; inside, moves between items.
HomeorEnd
Moves to the first or last menu item.
ArrowRightorArrowLeft
Drills into a field's values, or goes back to fields.
Letters
Typeahead jumps to the matching item.
Escape
Closes the menu and returns focus to the trigger.
  • The toolbar is role="group"; the menu panel is a labelled role="dialog" holding a role="menu" of checkable items.
  • Remove buttons are labelled like "Remove Status: Open", and removing a chip moves focus to its neighbor or the Add filter trigger.
  • Additions and removals are announced through a role="status" region.
  • Chips open and close their slot on a spring so neighbors glide; values morph in place.
  • The Add filter trigger morphs into the menu surface and steps slide between fields and values.
  • Reduced motion replaces the morphs and slides with instant changes and short fades.
  • Below 520px the toolbar stacks into a column with actions aligned to the end.
  • The menu panel is min(16rem, 100vw minus a gutter) wide, flips its edge when there is no room, and its list caps at min(20rem, 55vh).
  • Hover highlights apply only on hover-capable fine pointers.
  • Several ResizeObservers measure chips and the menu for morphs; menu options are not virtualized, so keep value lists short.

Notes for AI

Give your coding assistant the Markdown reference instead of screenshots.

  • Use above tables and lists for faceted filtering. Use chip-group for a fixed set of toggles and search-field for free text.
  • Keep one chip per field: onAdd receives a chip keyed by field id, so replace any existing chip with that id.
  • Pair with sortable-data-table and pagination for a full list view.

The full library index for assistants is at /llms.txt.