Skip to content
buttery

v1.0.0

Source on GitHub

Version 1.0.0

FilterBar

A row of filter pills over a list that wrap as they're applied, with Clear filters and actions, folding into one button on a phone.

import { FilterBar } from "@butteryui/react";

Demo

When to use it

Use it for

  • Filtering a table by its fields: status, date, customer
  • Showing which filters are applied, each removable

Not for

  • Named sets of filters people return to: use SavedViews
  • One search box: use SearchField

Examples

Applied filters

Several filters applied at once: the pills wrap, each one removable, and Clear filters takes them all away.

Showing 2 of 8 orders

Order filters

Filters over a list of orders: pick a status from its pill, clear it, or export what's shown.

5 of 5 orders

#1041 路 Larkspur Caf茅 路 Paid

#1042 路 Northgate Bakery 路 Unpaid

#1043 路 Wren Street Deli 路 Paid

#1044 路 Saltmarsh Kitchen 路 Refunded

#1045 路 Copperleaf Books 路 Unpaid

Orders table

A filter bar over an orders table: a status pill, and a search among its actions.

5 of 5 orders

Order
Customer
Status
Total
ORD-3101
Larkspur Caf茅
Paid
$64.00USD
ORD-3102
Northgate Bakery
Unpaid
$38.00USD
ORD-3103
Wren Street Deli
Paid
$112.00USD
ORD-3104
Saltmarsh Kitchen
Refunded
$21.00USD
ORD-3105
Larkspur Caf茅
Unpaid
$47.00USD

Variants and states

Filters

Applied pills are solid with a remove button; press one for its editor. Under 640px they fold into one button.

Props

FilterBar

PropTypeDefaultDescription
labelstring"Filters"Names the filters for screen readers. Defaults to "Filters".
actionsReactNodeActions at the end of the first line, such as Export.
onClearAll(() => void)Called by "Clear filters", which shows once any filter is applied.
clearLabelstringNames "Clear filters".
appliednumberHow many filters are applied, for "Clear filters" and the folded button's count. Counted from the FilterPills among the children (through fragments) when left out; pass it when your pills sit inside components of your own.
childrenReactNodeThe filters, FilterPills.

It also takes ComponentPropsWithRef<"div">.

FilterPill

PropTypeDefaultDescription
label

required

stringThe field it filters, such as "Status".
valuestringWhat it's set to, such as "Paid". Leave it out while the filter isn't applied.
onRemove(() => void)Removes the filter. The applied pill shows a remove button that calls it.
childrenReactNodeThe filter's editor, in a popover the pill opens.
openbooleanWhether its popover is open. Pair with onOpenChange to control it, such as to close it once a value is picked.
defaultOpenbooleanfalseWhether its popover starts open when uncontrolled. Defaults to false.
onOpenChange((open: boolean) => void)Called when its popover opens or closes.
removeLabelstringNames the remove button. Defaults to "Remove" and the field's name.

It also takes Omit<ComponentPropsWithRef<"div">, "children">.

Accessibility

A group named Filters. Each pill is a button named by its field and value ("Status: Paid", shown as "Status | Paid") that opens its editor in a popover; an applied pill's remove button is named Remove and the field, with a 24px press area. On a phone the pills move behind one Filters button that says how many are applied.

KeysWhat they do
Enter or SpaceOpens a pill's editor, removes a filter from its remove button, clears them all from Clear filters, or, folded on a phone, opens the pills
EscapeCloses the open editor and puts focus back on its pill

Motion

It appears with a `Presence` preset and leaves faster than it came, in about 60% of the time.

With reduced motion: A pill's editor, and the folded pills on a phone, fade in and out in 100ms without growing.

Layout

It takes its container's width: the pills sit 8px apart and wrap onto more lines as filters are applied, the actions stay at the end of the first line, centered level with the pills while those fit on one line, and under 640px of its own width the pills fold into one "Filters 路 2" button. Each pill is 28px tall (--bt-h-sm) and truncates its "Field | value" with the full text in its title, and its 16px remove button has a 24px press area.

See it in the roastery demo's customers and orders.