Filter dropdown
The compact workflow filter on the Recommendations page: the chosen option on a small button, and a list with a count beside each option.
import { FilterDropdown } from "@/pages/recommendations/index";FilterDropdown narrows a list to one option, such as one workflow, and shows how many items each option has. The button shows only the chosen option, with no label in front of it, so it fits a narrow header. The list is the product dropdown menu.
Usage
It sits at the right of the Decision queue header on the Recommendations page. The counts are the open recommendations for each workflow, after the channel filter is applied.
<FilterDropdown
ariaLabel="Filter by workflow"
size="sm"
value={scope}
onChange={pickScope}
options={chips.map((c) => ({
value: c.id,
label: c.id === "all" ? "All workflows" : c.name,
count: c.count,
}))}
/>Sizes
size is passed to the Button. sm is the default and the only size the product uses. Both sizes have 12px text, because FilterDropdown overrides the small button's 10px.
<FilterDropdown ariaLabel="Filter by workflow" size="sm" align="left" value={scope} onChange={setScope} options={options} />
<FilterDropdown ariaLabel="Filter by workflow" size="md" align="left" value={scope} onChange={setScope} options={options} />Long names
The button is at most 180px wide and cuts a longer name short with an ellipsis. The list is at least 240px wide and shows the whole name, and both carry it as a title, so hovering shows it in the browser's own tooltip. The list scrolls after 320px.
<FilterDropdown ariaLabel="Filter by workflow" value="delivery-leaks" onChange={setScope} options={options} align="left" />Anatomy
| Part | Style |
|---|---|
| Button | Button variant="secondary": white, --color-primary-500 border and text. 12px text, CaretDown after the label, at most 180px wide. |
| List | The dropdown menu panel, at least 240px wide and at most 320px tall. It lines up with the button's right edge by default. |
| Option | The optional icon, then the name (14px, weight 500 when chosen), then the count in 12px --text-muted with tabular figures. |
| Selected | A 16px bold Check in --color-primary-500 after the count. |
Props
| Prop | Type | Default | Notes |
|---|---|---|---|
value | string | The value of the chosen option. If none matches, the button shows the first option. | |
options | Option[] | See below. | |
onChange | (value) => void | Called with the option's value on every pick, including the one already chosen. | |
ariaLabel | string | Becomes the button's aria-label. See Accessibility. | |
size | "sm" | "md" | "sm" | The Button size. |
align | "right" | "left" | "right" | Which edge of the button the list lines up with. Any value other than "right" lines it up on the left. |
| Option field | Type | Notes |
|---|---|---|
value | string | Compared with value. |
label | string | Shown on the button when chosen, and in the list. |
count | number | Optional. Shown on the right of the row, including 0. |
icon | React element | Optional, placed before the name. Pass an element (<Flask size={16} />), not a component. No caller uses it today. |
Accessibility
- The menu is Base UI's: arrow keys, typing to jump, Enter to pick, and Escape to close and return focus to the button.
ariaLabelreplaces the button's text as its accessible name. A screen reader hears "Filter by workflow" and not the chosen workflow, and someone using voice control cannot say the words they see on the button. Until this changes, include the value:ariaLabel={"Filter by workflow: " + selected.label}.- The chosen option is shown only by its weight and the tick. It has no
aria-checkedoraria-current. - The full name of a cut-short option is only in a
title, which does not show on keyboard focus.
When to use it
Use it only where it is used today. For a new filter, use a Composer menu or the filter in Menus and filters: they name what they filter on the button, use the quieter secondaryGhost button, and are reached by keyboard and screen reader in the same way.
| FilterDropdown | Composer menu | |
|---|---|---|
| Button | Blue secondary, the value only | Grey secondaryGhost or ghost, label and value |
| Counts | Right-aligned in their own column | Written into the label |
| Second line | No | Optional description |
| Long names | Cut at 180px | Not cut |
Do and don't
- Do make the first option the unfiltered one, such as "All workflows", and give it the total.
- Do keep counts as the number of items the person still has to act on, so they add up.
- Don't use it for actions or navigation. Every option sets the filter.
- Don't put two FilterDropdowns side by side. Without a label on the button, people cannot tell them apart.
Where it is used
| File | Use |
|---|---|
src/pages/recommendations/index.jsx | The workflow filter in the Decision queue header. The choice is kept in the page's scope state, which starts from the ?workflow= URL parameter. |
The function is defined in that file and exported from it for these docs.