FilterBar
Single select
Multiple select
value, defaultValue, and onValueChange use a string, or string[] with multiple
(filters, value and defaultValue also take readonly arrays).
The callback receives the complete selection. Clear with "" (single) or [] (multiple).
import { useState } from "react";
const [active, setActive] = useState<string[]>(["FRIENDLY"]);
<FilterBar
filters={["FRIENDLY", "HOSTILE", "NEUTRAL"]}
multiple
value={active}
onValueChange={setActive}
ariaLabel="Track classes"
/>;
Use disabled to block both keyboard and pointer changes without discarding the selected filters.
Native div attributes reach the group element: id, data-*, title, tabIndex, focus, blur and key handlers, and the rest. Handlers run before React Aria's own, so arrow-key movement keeps working. Three are not applied: role and aria-orientation, because the group is a radio group (single) or a toolbar (multiple) whose filters wrap, and dangerouslySetInnerHTML, because the filters come from filters; in development a structured PROP_NOT_APPLIED error says so.
Layout
When the filters do not fit, they wrap onto more rows and the bar grows taller, so every filter stays visible and the bar never widens its container. A long label wraps inside its filter, which grows to hold it, and an unbroken one breaks anywhere. Each label in filters is shown once.
A selection the list does not offer
A selected value that is not in filters (a retired class, a saved view restored from a link, a list built from the data loaded now) shows at the end of the bar as a selected filter marked Unavailable, so the bar never hides an active filter. In multiple mode the operator clears it like any other filter; in single mode choosing another filter replaces it. When it goes, keyboard focus moves to the filter in its place. In development a structured UNKNOWN_FILTER_VALUE error names the value; add it to filters if it is still offered. In multiple mode an empty string in the selection (an empty query parameter split on commas gives [""]) is such a value too: it shows as a dash, "—", marked Unavailable, and is reported the same way. In single mode "" still means no selection.
<FilterBar
filters={["FRIENDLY", "HOSTILE", "NEUTRAL"]}
multiple
value={["FRIENDLY", "RETIRED"]}
onValueChange={setActive}
ariaLabel="Track classes"
/>
// FRIENDLY and RETIRED (Unavailable) are selected; pressing RETIRED reports ["FRIENDLY"].
Props
| PROP | TYPE | DEFAULT | REQUIRED |
|---|---|---|---|
filtersReadonly string[] of filter labels, each shown once, in order. | array | — | yes |
valueControlled selection: string in single mode; readonly string[] when multiple=true. Use an empty string or array to clear the corresponding mode. A selected value that is not in filters shows at the end of the bar as a selected filter marked unavailable, which the operator can remove. | string | array | — | no |
defaultValueInitial uncontrolled selection: string in single mode; readonly string[] when multiple=true. | string | array | — | no |
multipleWhen true, value, defaultValue, and onValueChange use string[] and a selected filter can be cleared; otherwise they use string and the filters are radios, so the active filter stays selected until another is chosen. | boolean | false | no |
ariaLabelAccessible name for the group. | string | "Filters" | no |
disabledDisable pointer and keyboard selection while retaining the active filters. | boolean | false | no |
onValueChangeReceives the active string in single mode or the complete string[] selection when multiple=true. | function | — | no |
className | string | — | no |
Accessibility
- Name the group with
ariaLabel. Single selection usesradiogroup/radio; multiple selection uses toggle buttons. - Arrow keys move focus. Space or Enter selects a filter. In single mode the filters are radios: the active filter stays selected until another is chosen. In multiple mode Space or Enter also clears a selected filter.
- Selection adds
data-selected, accent fill, andaria-checked(single) oraria-pressed(multiple). Unselected filters have the control outline. Filters have visible focus rings. - In forced-colors (high contrast) mode the selected filter is drawn in the system highlight color, a disabled selected one in the system's disabled color, and focus as an outline.
- An unavailable value carries the written cue "Unavailable" and its accessible name is
RETIRED, Unavailablefor a valueRETIRED.
Manifest entry
<FilterBar filters={["ALL","FRIENDLY","HOSTILE","NEUTRAL","UNKNOWN"]} defaultValue="ALL" />View agent manifest
{
"description": "Toggle-button filters for a view, wrapping onto more rows when they do not fit. Single-select by default; set multiple for multi-select.",
"props": {
"filters": {
"type": "array",
"required": true,
"description": "Readonly string[] of filter labels, each shown once, in order."
},
"value": {
"type": "union",
"types": [
"string",
"array"
],
"description": "Controlled selection: string in single mode; readonly string[] when multiple=true. Use an empty string or array to clear the corresponding mode. A selected value that is not in filters shows at the end of the bar as a selected filter marked unavailable, which the operator can remove."
},
"defaultValue": {
"type": "union",
"types": [
"string",
"array"
],
"description": "Initial uncontrolled selection: string in single mode; readonly string[] when multiple=true."
},
"multiple": {
"type": "boolean",
"default": false,
"description": "When true, value, defaultValue, and onValueChange use string[] and a selected filter can be cleared; otherwise they use string and the filters are radios, so the active filter stays selected until another is chosen."
},
"ariaLabel": {
"type": "string",
"default": "Filters",
"description": "Accessible name for the group."
},
"disabled": {
"type": "boolean",
"default": false,
"description": "Disable pointer and keyboard selection while retaining the active filters."
},
"onValueChange": {
"type": "function",
"description": "Receives the active string in single mode or the complete string[] selection when multiple=true."
},
"className": {
"type": "string"
}
},
"composable_with": [
"Card"
],
"never_inside": [
"Button",
"Badge"
],
"example": "<FilterBar filters={[\"ALL\",\"FRIENDLY\",\"HOSTILE\",\"NEUTRAL\",\"UNKNOWN\"]} defaultValue=\"ALL\" />"
}