All components (204)
Virtual list
Data · VirtualList
What it is and when to use it
A list of thousands of rows that does not clog the browser: only the visible ones exist in the DOM and the rest is reserved space. Measured with 5000 rows of 44 px: a dozen rows in the DOM.
When to use it
- Lists of thousands of items from which one or several are chosen: the year's orders, catalog products, postal codes.
- It needs a fixed
heightand all rows to be the same size (rowHeight, 44 px by default): without those two things it is not known which piece to draw. Withdescriptionon the rows, raiserowHeight. loadingwhile more rows arrive: the list is marked busy and below it a row withloadingTextappears.
When not to
- A few hundred rows:
SelectableList, which does not ask for a fixed height or equal rows. - Data in columns that are sorted and filtered:
Table. - A list that keeps growing at the end:
LoadMoreButton.
Keyboard: Tab enters the list with focus on the chosen row (or the first). The arrows move through the rows skipping disabled ones, Home and End go to the ends and typing jumps to the row that starts that way; Enter or Space choose the row with focus (with multiple, they check and uncheck). If the row being moved to is out of view, the list scrolls to it. Disabled rows cannot be chosen.
Accessibility: it is the same listbox as SelectableList, with a required name (label) and each row as an option with its aria-selected. Each row carries aria-posinset and aria-setsize with the real total: otherwise the reader would count only the painted rows and say "1 of 12" with thousands behind. The chosen mark is in addition to the background.
Fine-tuning: no variables of its own: it shares the classes of SelectableList (amset-list-sel__option, amset-list-sel__detail) and adds amset-virtual.
What it looks like
2000 orders, and only the visible ones are rendered.
<VirtualList
label="Orders this year"
rows={pedidos}
height="18rem"
rowHeight={60}
value={elegido}
onChange={setElegido}
/>Props
Import it with import { VirtualList } from '@amset/ui'. Required props are marked.
| Prop | Type | What it does |
|---|---|---|
heightrequired | string | Height of the visible window. It is required: without a height there is nothing to virtualize. |
labelrequired | string | Required: without a name it is just "list". |
rowsrequired | readonly VirtualRow[] | — |
className | string | Merged with the library classes; it does not replace them. |
empty | ReactNode | — |
loading | boolean | The rows are arriving (infinite scroll asks for more). The list is marked busy and a `loadingText` row is shown below. |
loadingText | string | What the loading row says. "Loading…" by default. |
onChange | ((key: string | null) => void) | ((keys: readonly string[]) => void) | — |
renderOption | OptionRender<VirtualRow> | Paints the inside of each row: an avatar, two lines, a price. What the screen reader READS is still `label`; this is only what is seen. It is called only for the painted rows, not for all 5,000. |
rowHeight | number | — |
selection | "multiple" | "single" | — |
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:
