Components / Data display

FilterToolbar

Keep collection filters close and easy to reset.

Install

npx shadcn@latest add https://irisui.dev/r/filter-toolbar.json
import { FilterToolbar } from "@/components/iris/filter-toolbar/filter-toolbar";
Registry item filter-toolbarBrings in foundationRegistry JSON

Preview

FilterToolbar

A row of removable filter chips with "Clear all" and an optional "Add filter" button that grows into a two-step field-then-value menu.

When to use

  • Above lists and tables to show which filters are applied and let people drop them one by one.
  • When filters are discrete field/value pairs (Status · Available, City · Athens).
  • FilterMenu is also exported on its own when you only need the add-filter morphing menu.
  • Use SearchField for free-text search, and ChipGroup for a fixed set of toggleable options.

Usage

import { FilterToolbar } from "@/components/iris/filter-toolbar/filter-toolbar";

const [filters, setFilters] = useState([{ id: "status", label: "Status", value: "Available" }]);
h(FilterToolbar, {
  label: "Listing filters",
  filters,
  onRemove: (id) => setFilters((f) => f.filter((x) => x.id !== id)),
  onClearAll: () => setFilters([]),
  addFilter: {
    fields: [
      {
        id: "status",
        label: "Status",
        options: [
          { value: "Available", hint: 214 },
          { value: "Occupied", hint: 42 },
        ],
      },
      { id: "city", label: "City", options: ["Athens", "Thessaloniki", "Berlin", "Munich"] },
    ],
    // chip.id is the field id, so a second pick for a field replaces the first
    onAdd: (chip) => setFilters((f) => [...f.filter((x) => x.id !== chip.id), chip]),
  },
});

Props

Prop Type Default Description
filters FilterChip[] — (required) Applied filters: { id: string; label: string; value?: string }, shown as "label · value".
onRemove (id: string) => void — (required) Remove one chip.
onClearAll () => void — Called by "Clear all" (shown while any filter is applied).
addFilter { fields: FilterField[]; onAdd: (chip, field) => void; label?: string; align?: "start" | "end" } — Adds the Add filter trigger. FilterField = { id; label; icon?; options: (string | { value; label?; hint?; icon? })[] }.
children ReactNode — Extra controls placed in the action area (e.g. a sort menu).
label string "Active filters" Accessible name of the toolbar group.

FilterMenu props: fields, onSelect(chip, field), active?: FilterChip[] (marks current values), label? (default "Add filter"), align? (default "end").

Notes

  • Removing a chip moves focus to its neighbour, or to the Add filter trigger when none are left; changes are announced through a polite live region.
  • The menu is a dialog with arrow-key navigation (Up/Down, Home/End, Right/Left to enter and leave a field) and Escape to close.
  • The menu panel renders in place, not in a portal, so keep ancestors free of overflow: hidden, and leave room below the toolbar for it.
  • Chips enter and leave by growing/collapsing their slot; reduced motion makes changes instant.