Use when you need to choose multiple items from a list.
Choose multiple items from a list
A Multi-select Input is a form component that allows users to select multiple items from a predefined set of options. It differs from an autocomplete (which suggests options for freeform entry) by working with a bounded, known list of options — users can only select what exists in the list.
The most common visual implementation is a tag/chip-based selector: selected items appear as removable tags inside the input field, and remaining options are shown in a dropdown. Additional patterns include checkbox lists, dual listboxes, and native <select multiple>.
references/pattern.md, then choose the smallest viable variation.| Key | Action |
|---|---|
Tab | Moves focus to the multi-select input; Shift+Tab moves backward |
Down Arrow | Opens the dropdown; moves focus down through options |
Up Arrow | Moves focus up through options |
Enter | Selects / deselects the focused option |
Space | Selects / deselects the focused option (same as Enter in listbox) |
Escape | Closes the dropdown without changing selection |
Backspace | When search input is empty, removes the last selected tag |
<select multiple>The Problem:
Native <select multiple> requires Ctrl+Click (or Cmd+Click) to select multiple items, which is an unintuitive interaction that most users are unaware of.
<!-- Bad: Requires Ctrl+click — users don't know this -->
<select multiple name="skills[]">
<option>React</option>
<option>TypeScript</option>
</select>
How to Fix It? Use a custom multi-select component with checkboxes or a tag-based UI.
The Problem: If the dropdown closes every time the user selects an option, they must reopen it for each additional selection — significantly slowing down multi-item workflows.
How to Fix It? Keep the dropdown open after selection; close only on Escape or external click.
option.addEventListener('click', (e) => {
e.stopPropagation(); // Prevent close-on-outside-click from triggering
toggleOptionSelection(option);
updateTags();
searchInput.focus(); // Keep focus in the input
// DO NOT close the dropdown here
});
The Problem:
Users expect Backspace in an empty search input to remove the last selected tag. Omitting this makes the component feel incomplete and forces mouse usage.
How to Fix It? Listen for keydown on the search input.
searchInput.addEventListener('keydown', (e) => {
if (e.key === 'Backspace' && searchInput.value === '') {
const lastTag = getLastSelectedItem();
if (lastTag) {
removeSelection(lastTag);
}
}
});
For full implementation detail, examples, and testing notes, see references/pattern.md.
Pattern page: https://uxpatterns.dev/patterns/forms/multi-select-input