Components
TransferList
Move items between two sets with the keyboard: the ids on the right are the whole value, so a form saves one array.
Examples
Examples
Two panes, one value
`value` is the right-hand set. Name both panes: `sourceLabel` and `targetLabel` are the names a screen-reader user navigates by.
Available fields
- volumeBase units
- returnsLog return
- volatility20d realised
- regimeClassified state
Selected fields
- symbolTicker
- priceClose, adjusted
symbol, price
<TransferList
items={columns}
value={chosen}
onValueChange={setChosen}
sourceLabel="Available fields"
targetLabel="Selected fields"
/>Dense panes
Set `height` to the dense end when the list sits inside a panel or a settings row; 240 px is the default that keeps both panes scannable.
Available
- writeEdit the spec and save revisions
- publishPublish a revision
- adminChange members and policies
Granted
- readSee the run and its artifacts
- runQueue a backtest
<TransferList
items={permissions}
value={granted}
onValueChange={setGranted}
sourceLabel="Available"
targetLabel="Granted"
height={140}
/>Uncontrolled, with a starting set
With `onValueChange` omitted the component keeps its own selection; `defaultValue` decides where it starts.
Available
- publishPublish a revision
- adminChange members and policies
Granted
- readSee the run and its artifacts
- writeEdit the spec and save revisions
- runQueue a backtest
<TransferList
items={permissions}
defaultValue={["read", "write", "run"]}
sourceLabel="Available"
targetLabel="Granted"
height={200}
/>Usage
import { TransferList } from "@luc/ui";<TransferList items={columns} value={chosen} onValueChange={setChosen} />Items are `{ id, label, description? }` and the value is an array of ids, so the selection survives a re-render that rebuilds the item objects.
API
Read from the published TypeScript API, so a prop that is not listed here does not exist and a default that is listed is the one the compiler sees.
| Export | Kind | Signature |
|---|---|---|
TransferList | 7 documented props | ({ items, value, defaultValue, onValueChange, sourceLabel, targetLabel, height, className, ...props }: TransferListProps) => import("@types/react").JSX.Element |
TransferList props
Type: TransferListProps
Values the compiler reads from the declaration.
| Prop | Type | Default | Notes |
|---|---|---|---|
defaultValue? | readonly string[] | undefined | — | |
height? | number | undefined | — | Pane height in pixels. Default 240. |
items | readonly TransferItem[] | — | |
onValueChange? | ((ids: string[]) => void) | undefined | — | |
sourceLabel? | string | undefined | — | |
targetLabel? | string | undefined | — | |
value? | readonly string[] | undefined | — | Ids on the right-hand side. |
Guidelines
Do
- Use it when the order or the membership of a set is the value — column sets, watchlists, permissions.
- Name both panes with `sourceLabel` and `targetLabel`: they are the landmark names a screen-reader user navigates by.
- Set `height` to the dense end when the list sits inside a panel; 240 px is the default that keeps both panes scannable.
Don't
- Use a transfer list where a multi-select would do: two panes cost vertical space that a dropdown does not.
- Rely on drag and drop — this component moves items with buttons and the keyboard.
- Change the `items` prop identity on every render; the panes derive from it and the selection is keyed by id.
Accessibility
Both panes are labelled lists and every move is a real button, so the whole interaction is reachable by keyboard and announced — the buttons carry the item's name, not just an arrow glyph.
Usage
import { TransferList } from "@luc/ui";<TransferList items={columns} value={chosen} onValueChange={setChosen} />Guidelines
Do
- Use it when the order or the membership of a set is the value — column sets, watchlists, permissions.
- Name both panes with `sourceLabel` and `targetLabel`: they are the landmark names a screen-reader user navigates by.
- Set `height` to the dense end when the list sits inside a panel; 240 px is the default that keeps both panes scannable.
Don't
- Use a transfer list where a multi-select would do: two panes cost vertical space that a dropdown does not.
- Rely on drag and drop — this component moves items with buttons and the keyboard.
- Change the `items` prop identity on every render; the panes derive from it and the selection is keyed by id.
Accessibility
Both panes are labelled lists and every move is a real button, so the whole interaction is reachable by keyboard and announced — the buttons carry the item's name, not just an arrow glyph.
Related