Filter bar

Narrows a table, a log or a list in one row.

Part

  • bardefault

Filter

  • selectdefault

  • select, set

  • multiple, set

  • toggle

  • toggle, on

States

  • rest

  • hover

  • focus-visible

  • set

  • several set

  • disabled

Usage

When to use it
Use
Above a table or a list of jobs, partitions or runs longer than a screen, that a person narrows by text and by a few fields.
Use
In a Table's toolbar row, where it fills the row.
Not for
One search over a short list, with nothing else to narrow by. Use Input.
Not for
Switching between two to five views of the same thing. Use Segmented control.

Rules

7 rules
Must
Keep the bar to one row of 26px controls: the search, then the filters, then the count and Clear. Because every control at one height with one 1px edge reads as one ruled row; a 32px field or a second row of chips beside it breaks the line.
Never
Put a filter bar over a list that fits on one screen. Show one only once the rows run past a screen. Because six rows are read faster than they are filtered, so a search and two filters above them are a row of chrome that pushes the rows down.
Never
Put a primary Button in the bar, or style a set filter as one. Because a row of filters has no lead, and in dark a tint with a yellow line is the primary button, so a filter drawn that way reads as the action.
Must
Show the count with FilterBarCount, "128 of 1,204 jobs", whenever a filter can narrow the list. Because the count says the filters worked, and its status region tells a screen reader once typing pauses.
Should
Pass each option a count from useFilteredRows. Because the counts are taken against every other filter, so an option that would empty the list sinks under "None left" before it is picked.
Must
Give options their values as written: failed, eu-west-2, events_daily. Because the field is the label in capitals and the value is data; a capitalised region or table name is a different string from the one in the rows.
Should
Render FilterBarClear only while something is set. Because a Clear with nothing to clear is a dead control, and it hands focus back to the search when it goes.

State order

6 states, highest first
1
disabled
2
open
3
set
4
focus-visible
5
hover
6
rest

Accessibility

6 checks
The bar is role="search", named by aria-label.
A filter's name says its value: "Status: failed, queued"; the caret is decoration.
A quick filter is a toggle with aria-pressed; the selection wash is never the only sign, the name says what it does.
The count speaks once through a status region, 500ms after typing pauses.
Focus is Sodium's 2px gold ring 2px out on each cell; an open menu turns the cell white with its edge --focus doubled inward and a pale halo, as a field with the cursor in it.
In the menu the highlighted option lifts to white between two hairlines and a chosen one carries an ink check, no fill.

Keyboard

4 keys
/
Focuses the search from anywhere outside a field, dialog or menu.
Escape
In the search, clears it; in a menu, closes it.
Enter or Space
Opens a filter's menu, or turns a quick filter on or off.
Arrow keys
Move through a menu's options.

Edge cases

6 edge cases
Narrow bar, under 28rem
The search takes its own row; the filters, count and Clear go under it.
Very narrow, under 18rem
The count is only heard, not shown.
Long value
The cell ends its value in an ellipsis; the name keeps the whole value.
Several values chosen
The cell shows how many; the name lists them.
Option that would empty the list
Sinks below a rule under "None left with the other filters" and cannot be picked.
Dark theme
A set filter takes the dark yellow tint under text-1 with its rule edge, never a yellow line.

API

10 props
FilterBar
div props
FilterBarSearch value, onValueChange
string, (value) => void
FilterBarSearch shortcut
string | null default '/'
FilterBarSelect label, options
string, FilterOption[]
FilterBarSelect multiple
boolean default false
FilterBarSelect showAllOption, allLabel
boolean, string default false, 'All'
FilterToggle pressed, onPressedChange
boolean, (pressed) => void
FilterBarCount shown, total, noun
number, number, string
FilterBarClear
Button props default 'Clear'
useFilteredRows
(rows, {search, match, fields, filters, where}) => {rows, counts}

Tokens

24 tokens
--control-sm
26px
--field-bg
#f8f7f3
--field-hover
#fefefd
--field-edge
var(--line)
--field-edge-hover
#ecebe5
--field-ring-hover
#f4f3ee
--field-focus-bg
#ffffff
--field-ring-focus
#fff1b8
--field-inset-sm
7px
--row-highlight
#ffffff
--line
#e2dfd5
--focus
#7a5d00
--selected
#fff4bf
--selected-strong
#ffec99
--well
#f4f3ee
--text-1
#161512
--text-2
#55524a
--text-3
#6b675e
--text-disabled
#a8a499
--type-label-sm
400 12px/16px var(--font-mono)
--type-code-sm
400 12px/16px var(--font-mono)
--type-caption
400 13px/18px var(--font-sans)
--icon-sm
14px
--dur-state
120ms

Install

For your coding agent

GitHub

Please star me pookie

198

A new design system every week

Leave your email before you copy the prompt.