All components (204)
Transfer list
Choice · TransferList · .amset-transfer
What it is and when to use it
Two lists for distributing things: on the left what there is, on the right what is chosen, and in the middle the buttons that move what is marked or everything at once. For a user's permissions, a product's categories or a team's members.
When to use it
- Distributing a catalog of up to a few dozen items, when it helps to see at once what goes in and what stays out.
searchputs a field above each column, which filters only its own.- An item with
disabledinitemscan neither be marked nor moved: for what is imposed from outside. "Add all" and "Remove all" respect it. - What is added enters in the order of the catalog, not in the order in which it was pressed.
- It is controlled:
selectedsays what is on the right andonChangereceives the new keys after each move.
When not to
- Choosing several without needing to see what is left out:
MultiSelect, orSelectableListwithselection="multiple". - The filters of a catalog:
FilterGroup.
Keyboard: inside each list, the arrow keys move and Space or Enter mark and unmark. Tab passes from a list to the buttons in the middle and to the other list; a button with nothing to move is disabled and skipped.
Accessibility: the whole is a group named like the label, and each list is named with its title and its count ("Available: 7"). The arrow buttons have names: "Add to selected", "Add all to selected", "Remove from selected" and "Remove all from selected". Each move is announced ("2 added. 3 of 8 chosen."): without that, pressing an arrow makes no sound.
States and motion: the rows bring those of SelectableList (hover, pressed, checked with the tick that is drawn, focus inside, disabled) and the buttons, those of IconButton. What arrives in a column enters with a short fade and the count in the title jumps when it changes. When narrow the columns stack and the arrows turn sideways. disabled (data-disabled on the root) shows the distribution without allowing marking, searching or moving.
Sizes: sm, md (default) and lg apply to the rows (30, 36 or 44 px), the buttons, the search boxes and the titles, and change the minimum and maximum height of each list.
Fine-tuning: CSS variables on .amset-transfer: --amset-transfer-slot (between columns), --amset-transfer-title and --amset-transfer-count (their fonts), --amset-transfer-count-background and --amset-transfer-count-ink, --amset-transfer-height-min (both lists are at least this tall, so that the block does not jump around) and --amset-transfer-height-max (scrolling starts here; maxHeight changes it for both). The rows are adjusted with --amset-list-sel-*.
What it looks like
Available 2
Selected 1
<TransferList label="Permissions" items={items} selected={elegidos} onChange={setElegidos} />Props
Import it with import { TransferList } from '@amset/ui'. Required props are marked.
| Prop | Type | What it does |
|---|---|---|
itemsrequired | readonly TransferItem[] | — |
labelrequired | string | Required: it names the entire group ("User permissions"). |
onChangerequired | (keys: readonly string[]) => void | — |
selectedrequired | readonly string[] | Controlled: the keys that are in the right column. |
availableLabel | string | — |
className | string | Merged with the library classes; it does not replace them. |
disabled | boolean | Nothing is checked or moved: for viewing a distribution that cannot be changed. |
maxHeight | string | Maximum height of each list before scrolling. Without it, that of `--amset-transfer-height-max`. |
renderItem | OptionRender<TransferItem> | Paints each element of the two columns: an avatar with the name, a permission with its description in another tone. What the screen reader reads is still `label`. |
search | boolean | A search field above each column. |
selectedLabel | string | — |
size | "sm" | "md" | "lg" | Rows, buttons, search boxes and titles at once: `sm`, `md` (the default) or `lg`. Rows are 30, 36 or 44 px, like the rest of the controls. |
It also accepts the attributes of the element it renders: className, style, data-*, aria-* and its events.
CSS variables
These CSS variables are how you adapt it. Declare them on the component's selector, not on :root: the stylesheet redeclares them in the rule itself, and a declaration on the same element always wins.
| Variable | Default |
|---|---|
--amset-transfer-slot | var(--amset-space-3) |
--amset-transfer-title | var(--amset-text-sm) |
--amset-transfer-count | var(--amset-text-xs) |
--amset-transfer-count-background | var(--amset-divider) |
--amset-transfer-count-ink | var(--amset-ink-2) |
--amset-transfer-height-min | 11rem |
--amset-transfer-height-max | 14rem |
How to change it
.amset-transfer {
--amset-transfer-slot: ...;
--amset-transfer-title: ...;
}In the test bench
Every state and variant, to try one at a time, on its page at ui.amset.tech:
