All components (204)
Selectable list
Choice · SelectableList
What it is and when to use it
A list of options in plain view, not dropped down, to choose one or check several. Each option can carry a description, an icon and a detail on the right (an amount, a date, a counter), and the list can be divided into sections.
When to use it
- When the options have to be in front of you to compare them: an invoice template, a saved address.
selection="multiple"to check several rows of a short list and do something with them.maxHeightwhen the list is long: the scroll goes inside the list, not on the page.loadingwhile the options arrive: the list is marked busy and a row appears withloadingText("Loading…"); any that were already there stay.
When not to
- A long list inside a form:
Select, orSearchFieldif you need to search. - Distributing things between two columns:
TransferList, which already uses this list internally. - Data with columns that are sorted and filtered:
Table.
Keyboard: Tab enters the list with the focus on the chosen option (or on the first one). The arrow keys move, skipping disabled ones, Home and End go to the ends and typing jumps to the option that starts with those letters - accents are not needed: "e" finds "Éxito" -. Enter or Space choose; with multiple, they check and uncheck without releasing the others, and with Shift they check the whole span from the last one pressed. Disabled options cannot be chosen.
Accessibility: it is a listbox named like the label, and each option is an option with its chosen state. The description is read as the option's description; the icon is decorative. Without options, it shows the text of empty instead of leaving a blank gap.
States: each row darkens on hover and a little more when pressed; the chosen one has the soft accent background and the check mark is drawn when it is chosen (and erased, faster, when it is released). The keyboard focus is a 2 px ring inside the row, which the list clips when scrolling. Disabled rows are gray and have the not-allowed cursor. Rows that appear (on mount, on filtering) enter with a short fade.
Sizes: sm, md (the default) and lg: rows with a minimum height of 30, 36 or 44 px, with the font of the fields of the same size. With a finger no row goes below 44 px.
Fine-tuning: CSS variables on .amset-list-sel (VirtualList uses the same ones, except the row height, which there is its rowHeight):
- Measurements:
--amset-list-sel-height-row,--amset-list-sel-padding(on the sides),--amset-list-sel-padding-block(top and bottom),--amset-list-sel-slot(between rows),--amset-list-sel-radius(the box) and--amset-list-sel-radius-row. - Font and icons:
--amset-list-sel-font,--amset-list-sel-description(description, detail and empty state),--amset-list-sel-iconand--amset-list-sel-brand(the check mark). - Colors:
--amset-list-sel-background,--amset-list-sel-border,--amset-list-sel-hover,--amset-list-sel-selected(background of the chosen one),--amset-list-sel-ink-selectedand--amset-list-sel-color-brand.
The chosen mark always takes up space, so the rows do not jump when choosing.
What it looks like
<SelectableList
label="Invoice template"
options={[
{ key: 'basica', label: 'Basic invoice', description: 'No logo', detail: '12 uses' },
{ key: 'completa', label: 'Full invoice', description: 'With logo and legal footer' },
]}
initialValue="completa"
/>
<SelectableList label="Orders to print" selection="multiple" options={pedidos} maxHeight="14rem" />Props
Import it with import { SelectableList } from '@amset/ui'. Required props are marked.
| Prop | Type | What it does |
|---|---|---|
labelrequired | string | Which list this is. Required: without a name it is just "list". |
optionsrequired | readonly ListOption[] | readonly ListSection[] | The options as a flat list, or all of them grouped in sections (with their title). |
className | string | Merged with the library classes; it does not replace them. |
empty | ReactNode | Text when there is nothing. A blank gap looks broken. |
initialValue | string | readonly string[] | — |
loading | boolean | The options are arriving. The list is marked busy and a `loadingText` row is shown; those that were already there stay (searching for more, refreshing). |
loadingText | string | What the loading row says. "Loading…" by default. |
maxHeight | string | Maximum height before scrolling inside the list. |
onChange | ((key: string | null) => void) | ((keys: readonly string[]) => void) | — |
renderOption | OptionRender<ListOption> | Paints the inside of each option: an avatar, two lines, a price. What the screen reader READS is still `label` (and `description`); this is only what is seen. |
selection | "multiple" | "single" | — |
size | "sm" | "md" | "lg" | Row height and font size: `sm` (30 px), `md` (36 px, the default) or `lg` (44 px). With a finger no row goes below 44 px. |
value | string | readonly string[] | null | — |
It also accepts the attributes of the element it renders: className, style, data-*, aria-* and its events.
In the test bench
Every state and variant, to try one at a time, on its page at ui.amset.tech:
