Multi Select
Multi-value select with tag chips, inline search filtering, and keyboard navigation.
<arc-multi-select> Overview
>
MultiSelect is a form control that allows users to choose multiple values from a predefined list of options. Selected items appear as removable tag chips inside the control, giving clear visual feedback about what has been chosen. The inline text input doubles as a filter — typing narrows the dropdown to matching options, making it efficient even with large option sets.
Options are provided declaratively using `<arc-option>` child elements, each with a `value` and visible label. The dropdown opens on focus and filters in real time as the user types. Items can be toggled on and off by clicking or via keyboard navigation with ArrowUp/ArrowDown and Enter. Pressing Backspace when the text input is empty removes the last selected tag, providing a natural editing flow.
MultiSelect fires an `arc-change` event whenever the selection changes, with the current value array in the event detail. The component handles outside-click dismissal automatically and exposes CSS parts for `control`, `tag`, `input`, `dropdown`, and `option` to support targeted style customisation.Guidelines
When to use
- Always provide a `label` so the field is accessible to screen readers
- Use a descriptive `placeholder` to hint at expected input, such as "Choose languages..."
- Keep option labels concise so they display well as tags inside the control
- Listen to `arc-change` to react to selection changes and keep external state in sync
- Pre-populate the `value` array when editing existing records to show current selections
When not to use
- Do not use MultiSelect when only a single value is needed — use Select instead
- Do not provide more than ~50 options without also considering server-side filtering via arc-change
- Do not use extremely long option labels — they will overflow the tag chips and the dropdown
- Do not set both `disabled` and a pre-selected `value` without a clear visual explanation of why editing is blocked
- Avoid nesting MultiSelect inside a popover or modal without testing z-index stacking for the dropdown
Features
- Selected values rendered as removable pill-shaped tag chips inside the control area
- Inline type-ahead filtering that narrows the dropdown options in real time
- Full keyboard navigation: ArrowUp/Down to move, Enter to select, Escape to close, Backspace to remove the last tag
- Check marks next to already-selected options in the dropdown for clear state indication
- Declarative options via `<arc-option>` child elements with `value` and `label` attributes
- Automatic outside-click dismissal of the dropdown panel
- Focus glow on the control using the shared `--focus-glow` design token
- "No results found" empty state when the filter query matches no options
Preview
No results found
Usage
This component requires JavaScript. No pure HTML/CSS version is available — use the Web Component directly or a framework wrapper.
<arc-multi-select label="Languages" placeholder="Choose...">
<arc-option value="js">JavaScript</arc-option>
<arc-option value="ts">TypeScript</arc-option>
<arc-option value="py">Python</arc-option>
</arc-multi-select> import { MultiSelect, Option } from '@arclux/arc-ui-react';
export default function Example() {
return (
<MultiSelect label="Languages" placeholder="Choose...">
<Option value="js">JavaScript</Option>
<Option value="ts">TypeScript</Option>
<Option value="py">Python</Option>
</MultiSelect>
);
} <script setup>
import { MultiSelect, Option } from '@arclux/arc-ui-vue';
</script>
<template>
<MultiSelect label="Languages" placeholder="Choose...">
<Option value="js">JavaScript</Option>
<Option value="ts">TypeScript</Option>
<Option value="py">Python</Option>
</MultiSelect>
</template> <script>
import { MultiSelect, Option } from '@arclux/arc-ui-svelte';
</script>
<MultiSelect label="Languages" placeholder="Choose...">
<Option value="js">JavaScript</Option>
<Option value="ts">TypeScript</Option>
<Option value="py">Python</Option>
</MultiSelect> import { Component } from '@angular/core';
import { MultiSelect, Option } from '@arclux/arc-ui-angular';
@Component({
imports: [MultiSelect, Option],
template: `
<arc-multi-select label="Languages" placeholder="Choose...">
<arc-option value="js">JavaScript</arc-option>
<arc-option value="ts">TypeScript</arc-option>
<arc-option value="py">Python</arc-option>
</arc-multi-select>
`,
})
export class MyComponent {} import { MultiSelect, Option } from '@arclux/arc-ui-solid';
export default function Example() {
return (
<MultiSelect label="Languages" placeholder="Choose...">
<Option value="js">JavaScript</Option>
<Option value="ts">TypeScript</Option>
<Option value="py">Python</Option>
</MultiSelect>
);
} import { MultiSelect, Option } from '@arclux/arc-ui-preact';
export default function Example() {
return (
<MultiSelect label="Languages" placeholder="Choose...">
<Option value="js">JavaScript</Option>
<Option value="ts">TypeScript</Option>
<Option value="py">Python</Option>
</MultiSelect>
);
} API
-
size'sm' | 'md' | 'lg''md' - Control size. `md` is the default; `sm` and `lg` scale the control height and padding.
-
valuestring[][] - Array of selected option values. Updated when items are toggled and emitted via `arc-change`.
-
placeholderstring'' - Hint text shown inside the control when no items are selected and the input is empty.
-
labelstring'' - Visible label rendered above the control in a small uppercase style.
-
namestring'' -
disabledbooleanfalse - Disables the control, preventing interaction and reducing opacity to 50%.
-
readonlybooleanfalse - Prevents toggling options or removing chips while the control stays focusable; the dropdown can still be opened for viewing and the values still submit.
-
formAssociatedbooleantrue -
propertiesobject{ required: { type: Boolean, reflect: true }, readonly: { type: Boolean, reflect: true }, } - Lit merges static properties up the prototype chain, so every consumer gets these without declaring them. `required` participates in constraint validation below; `readonly` reflects for styling and is enforced by each component's interaction handlers (the mixin can't know which gestures mutate state).
-
autoValidatesbooleantrue - Components that run their own constraint-validation logic (pattern checks, range checks) opt out of the automatic required sync by overriding this to false, and own the whole validity flag set instead.
-
form -
validity -
validationMessage -
requiredbooleanfalse
Events
-
arc-changedetail: { value: string[] } - Fired when the selected values change
-
arc-inputdetail: { value: string } - Fired on every keystroke in the filter input. `event.detail.value` contains the current query text.
See Also
- Select Dropdown select with searchable options, keyboard navigation, and full ARIA listbox semantics for accessible form inputs.
- Combobox Searchable dropdown with type-ahead filtering.
- Chip A toggleable pill-shaped element for filters, tags, or multi-select options, with a selected state highlighted in accent-primary.
- Tag Compact pill-shaped label with color variants, custom color support, and an optional remove button, for categorisation, filtering, and selection feedback.