webdevpuneet.com

Transfer List — Dual List Box to Move Items Between Lists

Transfer List · Forms · Plain HTML, CSS & JS · Live preview

CategoryForms

Copy & paste

Source Code

<div class="tl" id="tl">
  <div class="tl-side">
    <div class="tl-head"><span>Available</span><span class="tl-count" data-for="available">0</span></div>
    <input class="tl-search" type="search" placeholder="Filter…" data-list="available" aria-label="Filter available">
    <ul class="tl-box" data-list="available" role="listbox" aria-multiselectable="true"></ul>
  </div>

  <div class="tl-controls">
    <button type="button" class="tl-btn" data-act="add-all" title="Move all right">&raquo;</button>
    <button type="button" class="tl-btn" data-act="add" title="Move selected right">&rsaquo;</button>
    <button type="button" class="tl-btn" data-act="remove" title="Move selected left">&lsaquo;</button>
    <button type="button" class="tl-btn" data-act="remove-all" title="Move all left">&laquo;</button>
  </div>

  <div class="tl-side">
    <div class="tl-head"><span>Selected</span><span class="tl-count" data-for="selected">0</span></div>
    <input class="tl-search" type="search" placeholder="Filter…" data-list="selected" aria-label="Filter selected">
    <ul class="tl-box" data-list="selected" role="listbox" aria-multiselectable="true"></ul>
  </div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Dual list box
Move items between Available and Selected pools.
Multi-select
Click to toggle multiple items, then move them together.
Move-all controls
Transfer the entire list in one click, in either direction.
Double-click move
Double-clicking an item sends it across instantly.
Per-list filtering
Each side has its own case-insensitive search box.
Smart button state
Controls disable when there is nothing to move.
Listbox ARIA
role=listbox/option with aria-selected for the multi-select model.
No library
Pure HTML/CSS/JS — no UI-kit transfer component.

About this UI Snippet

Transfer List — Dual List Box with Multi-Select, Filtering and Move-All

Screenshot of the Transfer List snippet rendered live

A transfer list — also called a dual list box — lets users move items between two lists: an "available" pool and a "selected" set. It's the classic control for assigning permissions, picking columns, building playlists, or choosing recipients. This snippet builds a complete one with multi-select, per-list filtering, move-selected and move-all buttons, and double-click-to-move, in plain HTML, CSS, and vanilla JavaScript.

A single source of truth

Both lists are rendered from one state object holding two arrays (available and selected) plus a selection set per side. Every action mutates those arrays and re-renders, so the UI can never drift from the data — there's no manual DOM shuffling that risks duplicate or orphaned items. Moving an item splices it out of one array and pushes it into the other, then re-sorts the destination so the lists stay alphabetised.

Multi-select and the four controls

Click an item to toggle its selection (highlighted), then use &rsaquo; to move the selected items right or &lsaquo; to move them left. &raquo; and &laquo; move everything at once. The buttons disable themselves intelligently: "move selected" is greyed out when nothing is selected on that side, and "move all" is greyed out when a side is empty — so the controls always reflect what's actually possible. Double-clicking an item moves it immediately, the shortcut power users expect.

Per-list filtering

Each side has its own search box that filters that list as you type, matching case-insensitively. Filtering is purely a view concern — it never changes the underlying arrays — so moving a filtered subset still works correctly and clearing the filter restores the full list. This matters when the available pool has dozens or hundreds of items.

Accessible structure

The lists use role="listbox" with aria-multiselectable, and each item is a role="option" carrying aria-selected, so assistive tech understands the multi-select model. The counts in each header announce how many items each side holds, and the move buttons have descriptive title attributes. Because everything is real, focusable markup, it's straightforward to extend with full keyboard navigation.

Responsive

On narrow screens the two lists stack vertically and the control column rotates to sit between them, so the same interaction works on a phone. The whole component is a couple of hundred lines with no dependencies, making it a clean, drop-in reference for the transfer-list pattern that UI kits charge a component for.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSTwo lists render — Available is populated, Selected starts empty.
  2. 2
    Set your itemsReplace the DATA array with your own labels (or objects, with a small tweak).
  3. 3
    Select and moveClick items to select, then use the ›/‹ buttons, or double-click to move one.
  4. 4
    Move everythingThe »/« buttons transfer all items at once between the lists.
  5. 5
    Filter long listsType in either search box to narrow that side as you go.
  6. 6
    Read the resultstate.selected holds the chosen items — submit or sync it as needed.

Real-world uses

Common Use Cases

Role and permission assignment
Pick capabilities for a user by moving them from an Available pool into Selected, with multi-select toggling and move-all controls.
Table column choices
Move columns in or out of view alongside a data table column toggle, filtering each pool by search.
Recipient lists
Build a send list from a directory of recipients, with double-click sending any single item across instantly without using the buttons.
Integration enablement
Enable a subset of services from a catalogue, linked to integration cards for details on each.
Tag assignment and settings
Assign many tags at once, or place inside a settings panel, with a single source of truth for both lists.

Got questions?

Frequently Asked Questions

It is a control with two side-by-side lists — an available pool and a selected set — and buttons to move items between them. It is ideal when users assign a subset from a larger collection, such as permissions, columns, or recipients, because it shows both what is chosen and what remains in one view, unlike a multi-select dropdown.

Read state.selected — it is the array of labels currently in the Selected list, kept sorted. Mirror it into a hidden input, post it with fetch, or bind it to your framework state at submit time. Because every move updates that array, it is always an accurate reflection of the UI.

No. The search boxes only change what is displayed; they never alter the underlying arrays. So if you filter the Available list and click "move all," only the visible behaviour you would expect is affected — the move operations work on the real state, and clearing a filter restores the full list intact.

Yes. Click several items to select them (they highlight), then use the move-selected button to transfer them together. The move-all buttons send the entire list across in one click, and double-clicking a single item is a quick shortcut to move just that one.

Hold the two arrays and the selection sets in component state and render both lists from them — useState (React), reactive refs (Vue), or component fields (Angular). The move and filter functions become methods that update state instead of calling render(); the framework re-renders for you. Keep the role=listbox/option markup for accessibility, and in Tailwind swap the classes for utilities.