JavaScript Transfer List
@lemonadejs/transferlist · ✓ 12 contract checks · framework-agnostic · zero dependencies
<Transferlist /> — two side-by-side lists with a middle column of
controls that move checked items between them (on the v6 contract
model).
Left list: the items NOT chosen, in data order. Right list: the chosen items, in chosen order. Each row carries a checkbox; the controls move all/checked items right/left and disable when nothing applies. Checked state is internal — one Set per side — and clears after every move.
bind=”${state}” holds the CHOSEN side’s values as an array. User moves commit through set() (fires onchange with the new chosen array); external writes stay silent. data is read BY REFERENCE: live data changes keep the chosen values that still exist.
Example
import { html } from 'lemonadejs';
import Transferlist from '@lemonadejs/transferlist';
const App = (props, { state }) => {
const members = state(['ana', 'marcus']);
const people = [
{ value: 'ana', label: 'Ana Souza' },
{ value: 'marcus', label: 'Marcus Lee' },
{ value: 'priya', label: 'Priya Patel' },
{ value: 'tom', label: 'Tom Becker' },
{ value: 'yuki', label: 'Yuki Tanaka' },
{ value: 'guest', label: 'Guest account', disabled: true },
];
return html`<div>
<${Transferlist} data="${people}" bind="${members}" search height="200"
titles="${['Company', 'Project team']}" />
<p>Team size: <b>${() => (members.value || []).length}</b></p>
</div>`;
};Installation
npm install @lemonadejs/transferlist
import Transferlist from '@lemonadejs/transferlist';
import '@lemonadejs/transferlist/style.css';
Three deployment forms, one component:
html`<${Transferlist} />` // by value (no registration)
setComponents({ Transferlist }); // then <Transferlist /> by name anywhere
createWebComponent(Transferlist); // <lm-transferlist> in plain HTML/any framework
Props
Every declared prop arrives as a live state — pass a value for a snapshot or a state for a two-way live wire. Attribute strings are coerced to the declared type.
| Prop | Type | Default | Description |
|---|---|---|---|
bind | array | — | Two-way bound value. .set() fires onchange; plain assignment is silent. the chosen values, as an array (two-way) |
data | array | — | TransferItem[] — strings/numbers normalize |
titles | array | ["Available","Chosen"] | |
search | boolean | false | a filter box above each list |
height | number | 280 | list viewport height (px, scrollable) |
Events
All event names are lowercase (the platform convention — LJS-305 warns otherwise).
onchange— (chosen) on user moves; external writes silent
API
import { ref } from 'lemonadejs';
const transferlist = ref();
html`<${Transferlist} ref="${transferlist}" />`;
// transferlist.current.getChosen(...) · transferlist.current.moveAll(...) · transferlist.current.reset(...)
getChosen()moveAll()reset()
Styling
All classes follow the lm-transferlist-* convention; visual variants are data-*
attributes on the root. Override freely — there is no styling engine to fight.
Contract
The machine-readable schema ships with the package:
import contract from '@lemonadejs/transferlist/contract.json';
verify.json carries the conformance proof produced by verify(Transferlist).
Looking for the v5 plugin? See the archived v5 documentation.