Filters

A filter bar of sentence-like chips with per-field operators and a two-step add menu

Composablebuilt onCombobox,Dropdown Menu,Popover,Scroll Area,Transition Panel,Text Morph,Tooltip,Kbd

The filter bar shows each active filter as a chip that reads like a sentence ("Status is In progress"). Use it on list and table views where people narrow results by several conditions at once.

For a single dropdown tied to a form field, use Combobox instead.

Preview

Status

Installation

Usage

Composition

Features

  • Picking a field in the add menu slides to its values, so a chip appears only once it has one.
  • Searching the menu also matches values across fields: type "done" to add "Status is Done" in one step.
  • Chips that outgrow the row scroll sideways, and the add and clear buttons stay in view.
  • A chip still waiting on its value shows a dashed edge and doesn't count as active.

Examples

Field types

Use type to pick each field's value control.

TypeControlValue
"select"Searchable list, one pickstring | null
"multiselect"Searchable list, many picksstring[]
"text"Inline inputstring
"number"Inline number input, two for betweennumber | null | NumberRange
"custom"Your control, rendered by renderValueunknown

Operators

Use operators to replace a field's operators or disabledOperators to hide some; each operator's shape picks its control.

ShapeControl
"scalar"The field's normal control (the default)
"range"Paired min and max inputs
"none"No value, as in is empty (valueless: true for short)
Status
Estimate
hrs
hrs

Multiselect

Use maxSelections to cap the picks and labels.selectedCount to word the "3 selected" summary.

Labels

Prefix and suffix

Use prefix and suffix on text and number fields for currency, units, or symbols.

Budget
$
Estimate
hrs

Controlled

Pass value and onValueChange to own the filters; FilterActiveCount shows how many are active.

[]

Overflow

Chips scroll sideways once they outgrow the row; set overflow="wrap" to flow them onto new rows instead.

Status
Priority
Title
Assignee
Estimate

Sizes

Use size to set the height of every chip in the bar.

Status
Status
Status

Variants

Use variant to pick the shell the chips and the add button sit on.

Status
Title
Status
Title
Status
Title
VariantDescription
outlineThe default. An outline Button's fill and border.
softA secondary Button's fill, for quieter toolbars.
elevatedA raised surface, for bars inside Cards and Dialogs.

A filter with no value yet shows a dashed border on every variant.

Keyboard shortcut

Set shortcut to a key that opens the add menu, ignored while typing or while a popup is open.

Press F (while not typing) to open the filter menu.

Empty state

Pass open and onOpenChange to FilterActionsAdd so a button outside the bar can open the add menu.

No filters yet

Narrow the list by status, title, or estimate.

Manual layout

Pass children to arrange the parts yourself.

URL state with nuqs

Wire value and onValueChange to nuqs to keep the filters in ?filters=, parsed back through asFilterValues.

Server-side filtering

onValueChange fires on every keystroke, so send only complete filters and let typing settle before you fetch.

State outside the bar

Use FiltersProvider and FiltersBar separately when UI outside the row (a results count, saved views) reads the same state through useFilters.

Accessibility

Keyboard

KeyWhereAction
Your shortcutAnywhere but a text fieldOpens the add menu
EnterAdd menuPicks the highlighted item, or adds a typed value
BackspaceEmpty add menu searchGoes back to the field list
EscapeAdd menuCloses it and returns focus to the add button
Backspace or DeleteA chip's remove buttonRemoves the filter and focuses the next chip
Arrow keysNumber inputSteps the value

Screen readers

  • Each chip is a group named after its filter, such as "Status is In progress", and each segment names itself.
  • A hidden status region announces adds, removes, and clears, since focus lands elsewhere.
  • The add menu flags an unreadable number with an "Enter a number" hint tied to the input.

Custom chips

Keep the filter-chip, filter-chip-remove, and filter-add slots on custom parts; keyboard removal and focus handoff look for them.

API Reference

Filters composes Cubby UI primitives and has no Base UI root of its own.

Props

Filters

FiltersProvider and FiltersBar in one. shortcut, overflow, and div props go to the bar; the rest go to the provider.

FilterAddButton

The add button and its menu. FilterActionsAdd is the same menu as a segment of FilterActions, and takes these props too.

FilterChip

Other parts

PartNotes
FiltersProviderOwns the state; takes the Filters props except shortcut and overflow.
FiltersBarThe row. Takes shortcut, overflow, and children; with children, pass shortcut to the add part.
FilterChipsRenders every chip, inside the scroll strip when overflow="scroll".
FilterActionsThe add and clear capsule. Pass children to add segments, styled with FILTER_SEGMENT classes.
FilterActionsClearThe capsule's clear segment. children replace its icon.
FilterClearButtonA standalone text clear button, hidden with no filters.
FilterActiveCount"3 active" text, counting complete filters, hidden at zero.
FilterChipValueRenders nothing for a valueless operator.

Handlers you pass to a part (onClick, onKeyDown, onBlur) run first; call event.preventDefault() to skip the built-in behavior.

Hooks

HookReturns
useFilters()Everything below; re-renders on every edit.
useFiltersState()filters.
useFiltersActions()Config and actions, stable while typing: addFilter, updateFilter, removeFilter, clearAll, getFilters, fields, fieldsById, labels, size, usedFieldIds.
useFilterChip()The current chip's filter, field, and size.

Types

FilterField

A union keyed on type. Every field has id, label, and optional icon, operators, and disabledOperators.

TypeAdds
select, multiselectoptions; multiselect also takes maxSelections
text, numberprefix, suffix, placeholder; number also takes step
customrenderValue, and optional defaultValue and formatValue

renderValue renders as its own component, so it can use hooks. formatValue turns the value into text for the chip's name; strings, numbers, and booleans work without it.

FilterValue

Helpers

HelperDoes
createFilter(field, partial?)A new filter with an id, the first operator, and an empty value.
patchFilter(field, filter, patch)Applies a patch, resetting the value when the operator's shape changes.
asFilterValues(json)Parses untrusted JSON (a URL param) into filters.
isFilterComplete(field, filter)Whether the filter narrows anything yet.
describeFilter(field, filter, names?)"Status is In progress".
formatFilterValue(field, filter)The value as text, "In progress".
operatorLabel(operator, names?)An operator's name, translated by labels.operators.
resolveOperators(field)A field's operators after operators and disabledOperators.
scalarOperatorFor(field)The first operator that takes one value.
withOption(field, value, option)Adds an option to a multiselect value, or replaces any other.