Transfer List
Accessible, unstyled dual-listbox transfer list with typed items, search, and bulk moves.
|
|
| Package |
@vizejs/ui/transfer-list |
| Maturity |
stable |
| Own the source |
vize lib pull transfer-list |
| Requires |
collection, composite-navigation, context, controllable-state, id, typeahead |
| Aliases |
transfer list, dual listbox, shuttle, list builder |
| Covers |
Ant Design Transfer, PrimeVue PickList, MUI Transfer List |
Usage
import { TransferList, TransferListRoot, TransferListAction, TransferListEmpty, TransferListItem, TransferListPanel, TransferListSearch } from "@vizejs/ui/transfer-list";
Or copy the source into your project with vize lib pull transfer-list (see Source Distribution).
API
TransferList<T>
Source: src/families/selection/transfer-list/transfer-list-root.vue
Props
| Prop |
Type |
Default |
Description |
id |
string | null |
undefined |
Consumer-owned base id. null and undefined select a deterministic fallback. |
items (required) |
readonly T[] |
required |
Every item, in canonical order; the source panel shows items not in the target. |
modelValue |
readonly T[] |
undefined |
Controlled target (right-hand) values. undefined selects uncontrolled behavior. |
defaultValue |
readonly T[] |
[] |
Initial target values for uncontrolled use and the value restored by reset. |
by |
TransferListBy<T> |
undefined |
Compare values by a property key or with a custom equality function. |
itemText |
(item: T) => string |
undefined |
Human-readable text used by search and typeahead. |
itemDisabled |
(item: T) => boolean |
undefined |
Keep individual items in place. |
filter |
TransferListFilter<T> |
undefined |
Search filter. Defaults to an accent- and case-insensitive "contains" match. |
sourceQuery |
string |
undefined |
Controlled source search text. |
targetQuery |
string |
undefined |
Controlled target search text. |
max |
number |
Infinity |
Maximum number of target values. |
orderMode |
TransferListOrderMode |
"append" |
append adds moved items at the end; source-order keeps items order. |
disabled |
boolean |
false |
Disable every panel, item, and action. |
name |
string |
undefined |
Form field name; each target value submits one hidden input. |
form |
string |
undefined |
Id of the owning form when rendered outside it. |
formValue |
(item: T) => string |
undefined |
Serialize a value for form submission. |
Events
| Event |
Payload |
Description |
update:modelValue |
[value: readonly T[]] |
Fired when the target list requests a new controlled value. |
change |
[ value: readonly T[], previous: readonly T[], moved: readonly T[], direction: TransferListDirection, nativeEvent: Event | null, ] |
Fired after a move: next target, previous target, moved items, direction, and the triggering event. |
update:sourceQuery |
[query: string] |
Fired when the source search text requests a new controlled value. |
update:targetQuery |
[query: string] |
Fired when the target search text requests a new controlled value. |
Slots
| Slot |
Slot props |
Description |
default |
TransferListSlotState<T> |
Panels, search fields, and action buttons. Receives both sides and capacity. |
Exposed
| Member |
Type |
Description |
moveToSource |
— |
|
moveToTarget |
— |
|
reset |
— |
|
target |
— |
|
TransferListRoot<T>
Source: src/families/selection/transfer-list/transfer-list-root.vue
Props
| Prop |
Type |
Default |
Description |
id |
string | null |
undefined |
Consumer-owned base id. null and undefined select a deterministic fallback. |
items (required) |
readonly T[] |
required |
Every item, in canonical order; the source panel shows items not in the target. |
modelValue |
readonly T[] |
undefined |
Controlled target (right-hand) values. undefined selects uncontrolled behavior. |
defaultValue |
readonly T[] |
[] |
Initial target values for uncontrolled use and the value restored by reset. |
by |
TransferListBy<T> |
undefined |
Compare values by a property key or with a custom equality function. |
itemText |
(item: T) => string |
undefined |
Human-readable text used by search and typeahead. |
itemDisabled |
(item: T) => boolean |
undefined |
Keep individual items in place. |
filter |
TransferListFilter<T> |
undefined |
Search filter. Defaults to an accent- and case-insensitive "contains" match. |
sourceQuery |
string |
undefined |
Controlled source search text. |
targetQuery |
string |
undefined |
Controlled target search text. |
max |
number |
Infinity |
Maximum number of target values. |
orderMode |
TransferListOrderMode |
"append" |
append adds moved items at the end; source-order keeps items order. |
disabled |
boolean |
false |
Disable every panel, item, and action. |
name |
string |
undefined |
Form field name; each target value submits one hidden input. |
form |
string |
undefined |
Id of the owning form when rendered outside it. |
formValue |
(item: T) => string |
undefined |
Serialize a value for form submission. |
Events
| Event |
Payload |
Description |
update:modelValue |
[value: readonly T[]] |
Fired when the target list requests a new controlled value. |
change |
[ value: readonly T[], previous: readonly T[], moved: readonly T[], direction: TransferListDirection, nativeEvent: Event | null, ] |
Fired after a move: next target, previous target, moved items, direction, and the triggering event. |
update:sourceQuery |
[query: string] |
Fired when the source search text requests a new controlled value. |
update:targetQuery |
[query: string] |
Fired when the target search text requests a new controlled value. |
Slots
| Slot |
Slot props |
Description |
default |
TransferListSlotState<T> |
Panels, search fields, and action buttons. Receives both sides and capacity. |
Exposed
| Member |
Type |
Description |
target |
readonly T[] |
Current target values. |
moveToTarget |
() => readonly T[] |
Move checked items to the target. |
moveToSource |
() => readonly T[] |
Move checked items back to the source. |
reset |
() => boolean |
Restore defaultValue. |
TransferListAction
Source: src/families/selection/transfer-list/transfer-list-action.vue
Props
| Prop |
Type |
Default |
Description |
action (required) |
TransferListAction |
required |
Move checked or all visible items in one direction. |
ariaLabel |
string |
undefined |
Accessible name; defaults to an English description of the action. |
Slots
| Slot |
Slot props |
Description |
default |
{ readonly enabled: boolean } |
Button content such as an arrow icon. Receives availability. |
TransferListEmpty
Source: src/families/selection/transfer-list/transfer-list-empty.vue
Props
| Prop |
Type |
Default |
Description |
side (required) |
TransferListSide |
required |
Panel whose emptiness this message reports. |
Slots
| Slot |
Slot props |
Description |
default |
{ readonly query: string; readonly filtered: boolean } |
Message shown while the panel has no visible items. Receives the search text. |
TransferListItem<T>
Source: src/families/selection/transfer-list/transfer-list-item.vue
Props
| Prop |
Type |
Default |
Description |
id |
string | null |
undefined |
Consumer-owned option id. null and undefined select a deterministic fallback. |
value (required) |
T |
required |
Item value from the panel's items. |
textValue |
string |
undefined |
Typeahead text; defaults to the root itemText. |
Slots
| Slot |
Slot props |
Description |
default |
TransferListItemSlotState<T> |
Item content. Receives checked, active, and disabled state. |
Exposed
| Member |
Type |
Description |
checked |
— |
|
element |
Readonly<ShallowRef<HTMLElement | null>> |
Template ref to the rendered root element. |
TransferListPanel
Source: src/families/selection/transfer-list/transfer-list-panel.vue
Props
| Prop |
Type |
Default |
Description |
side (required) |
TransferListSide |
required |
Which list this panel shows: available (source) or chosen (target) items. |
ariaLabel |
string |
undefined |
Accessible name, e.g. "Available" or "Selected". |
ariaLabelledby |
string |
undefined |
Space-separated ids of a visible panel heading. |
Slots
| Slot |
Slot props |
Description |
default |
TransferListPanelSlotState<unknown> |
Render one TransferListItem per visible item. Values are untyped here; the root slot exposes the same lists typed as T. |
TransferListSearch
Source: src/families/selection/transfer-list/transfer-list-search.vue
Props
| Prop |
Type |
Default |
Description |
side (required) |
TransferListSide |
required |
Panel this field filters. |
placeholder |
string |
undefined |
Hint text shown while empty. |
ariaLabel |
string |
undefined |
Accessible name, e.g. "Search available". |
Behavior
Contract
TransferList is a headless, strongly typed dual listbox. transfer-list-root.vue
is generic over the item type T: items holds every item, v-model holds the
target (right-hand) values as readonly T[], and the source panel shows the
rest. transfer-list-panel.vue renders one multiselectable role="listbox"
per side with active-descendant navigation and typeahead from the shared
collection registry and composite navigation. transfer-list-item.vue
renders role="option" where aria-selected means "checked for moving".
transfer-list-search.vue filters one panel, transfer-list-action.vue moves
checked or all visible items, and transfer-list-empty.vue reports an empty
panel. Named lists submit one hidden input per target value. No CSS ships.
Normative Behavior
| # |
State |
Input |
Outcome |
Proven by |
| T1 |
any |
render |
two multiselectable listboxes split items by the target model; hidden inputs mirror the target |
renders two multiselect listboxes that split items by the target model |
| T2 |
source |
click items / "Add selected" |
toggles checked state (never for disabled items), moves checked items, emits change(value, previous, moved, direction, event) |
clicking checks items and the selected action moves them, emitting the move |
| T3 |
source-order |
move / "Add all" / "Remove all" |
keeps canonical order, skips disabled items, disables the action when nothing can move |
source-order mode keeps canonical order and move-all skips disabled items |
| T4 |
max |
"Add all" |
moves only up to max, publishes data-full, disables further adds |
max caps the target and disables moving further items |
| T5 |
search |
type / Escape / ArrowDown |
filters one panel accent-insensitively, move-all moves only visible items, empty state distinguishes filtering, Escape clears, ArrowDown enters the panel |
search filters one panel accent-insensitively and drives the empty state |
| T6 |
panel focused |
arrows / Home / Space / Shift+Arrow / Ctrl+A / Enter |
navigates skipping disabled items, toggles, extends checks, checks all visible, moves checked (or the active item); the highlight recovers to a neighbour |
keyboard: navigation, Space toggles, Shift+Arrow extends, Ctrl+A, Enter moves |
| T7 |
any |
double-click / printable key |
moves one item; typeahead highlights by text |
double-click moves an item and typeahead finds items by text |
| T8 |
controlled |
move |
emits and waits for the parent |
controlled target waits for the parent |
| T9 |
disabled |
any |
panels leave the tab order; items, actions, and search are inert |
disabled transfer lists block every interaction |
| T10 |
any |
exposed API |
moveToTarget, moveToSource, reset share state |
exposed methods move checked items |
| T11 |
no provider |
mount a part |
throws VIZE_UI_CONTEXT_MISSING |
parts require a TransferList provider |
| T12 |
pure helper |
transferItems |
respects max, order modes, and direction |
transferItems respects max, order modes, and direction |
SSR
Panel ids derive from the root id; markup is byte-identical across isolated
requests and hydrates without warnings (renders byte-identical TransferList markup across isolated SSR requests, hydrates TransferList without mismatches or node replacement).