Loading Developer Playground

Loading ...

Skip to main content
ARIA ATTRIBUTEβ€’Widget Attributes

aria-multiselectable

Indicates that the user may select more than one item from the current selectable descendants. Essential for accessible multi-select listboxes, grids, and tree views.

Value Type
true | false
Common Use
Multi-Select Lists
Used With
aria-selected

Overview

The aria-multiselectable attribute indicates that more than one item can be selected from a group of selectable items. Screen readers announce this as "multi-selectable" to help users understand they can choose multiple options.

This attribute is used on container elements like listbox, grid, tree, and tablist. The individual items within use aria-selected to indicate their selection state.

Keyboard Conventions

Multi-select widgets typically support Ctrl/Cmd + Click for toggling individual items and Shift + Click for range selection. Ctrl/Cmd + A often selects all items.

Live Demo: Multi-Select Listbox

Select programming languages:
  • JavaScript
  • TypeScript
  • Python
  • Go
  • Rust
  • Java

Selected: 0 of 6 (None)

0 items selected

Screen reader: "Select programming languages, listbox, multi-selectable". When selecting: "JavaScript, selected, 1 of 6". When toggling: "TypeScript, not selected".

Attribute Values

true

Multiple items can be selected simultaneously. Users can select/deselect items independently without clearing previous selections.

Screen reader: "[Label], listbox, multi-selectable"
false(default)

Only one item can be selected at a time. Selecting a new item automatically deselects the previously selected item. This is the default when the attribute is absent.

Screen reader: "[Label], listbox" (no multi-selectable announcement)

Code Examples

Multi-Select Listbox

<!-- Multi-select listbox -->
<label id="langs-label">Select programming languages:</label>
<ul 
  role="listbox" 
  aria-labelledby="langs-label"
  aria-multiselectable="true"
  tabindex="0"
>
  <li role="option" aria-selected="true">JavaScript</li>
  <li role="option" aria-selected="true">TypeScript</li>
  <li role="option" aria-selected="false">Python</li>
  <li role="option" aria-selected="false">Go</li>
  <li role="option" aria-selected="true">Rust</li>
</ul>

<!-- Screen reader: "Select programming languages, listbox, multi-selectable" -->
<!-- Per option: "JavaScript, selected, 1 of 5" -->

Single vs Multi-Select

<!-- Comparison: Single vs Multi-select -->

<!-- SINGLE SELECT (default behavior) -->
<ul role="listbox" aria-label="Choose one country">
  <!-- aria-multiselectable is absent or "false" -->
  <li role="option" aria-selected="false">USA</li>
  <li role="option" aria-selected="true">Canada</li>
  <li role="option" aria-selected="false">UK</li>
</ul>
<!-- Only ONE option can be selected at a time -->

<!-- MULTI-SELECT -->
<ul 
  role="listbox" 
  aria-label="Select countries to visit"
  aria-multiselectable="true"
>
  <li role="option" aria-selected="true">USA</li>
  <li role="option" aria-selected="true">Canada</li>
  <li role="option" aria-selected="false">UK</li>
</ul>
<!-- MULTIPLE options can be selected -->

Multi-Select Grid

<!-- Multi-select grid (like spreadsheet cells) -->
<table 
  role="grid" 
  aria-label="Data spreadsheet"
  aria-multiselectable="true"
>
  <thead>
    <tr>
      <th role="columnheader">Name</th>
      <th role="columnheader">Email</th>
      <th role="columnheader">Role</th>
    </tr>
  </thead>
  <tbody>
    <tr role="row" aria-selected="true">
      <td role="gridcell">John Doe</td>
      <td role="gridcell">john@example.com</td>
      <td role="gridcell">Admin</td>
    </tr>
    <tr role="row" aria-selected="true">
      <td role="gridcell">Jane Smith</td>
      <td role="gridcell">jane@example.com</td>
      <td role="gridcell">User</td>
    </tr>
    <tr role="row" aria-selected="false">
      <td role="gridcell">Bob Wilson</td>
      <td role="gridcell">bob@example.com</td>
      <td role="gridcell">User</td>
    </tr>
  </tbody>
</table>

<!-- Use aria-selected on rows for row selection -->
<!-- Use aria-selected on cells for cell selection -->

Multi-Select Tree

<!-- Multi-select tree (file browser) -->
<ul 
  role="tree" 
  aria-label="File browser"
  aria-multiselectable="true"
>
  <li 
    role="treeitem" 
    aria-selected="false"
    aria-expanded="true"
  >
    πŸ“ Documents
    <ul role="group">
      <li role="treeitem" aria-selected="true">πŸ“„ report.pdf</li>
      <li role="treeitem" aria-selected="true">πŸ“„ notes.txt</li>
      <li role="treeitem" aria-selected="false">πŸ“„ todo.md</li>
    </ul>
  </li>
  <li 
    role="treeitem" 
    aria-selected="false"
    aria-expanded="false"
  >
    πŸ“ Images
  </li>
</ul>

<!-- Shift+Click for range selection -->
<!-- Ctrl/Cmd+Click for individual toggle -->

React Component

// React Multi-select Listbox
import { useState, useCallback } from 'react';

function MultiSelectListbox({ 
  items, 
  label, 
  onChange,
  initialSelected = []
}) {
  const [selected, setSelected] = useState(new Set(initialSelected));
  const [activeIndex, setActiveIndex] = useState(0);

  const toggleSelection = useCallback((itemId, shiftKey) => {
    setSelected(prev => {
      const newSelected = new Set(prev);
      if (shiftKey && prev.size > 0) {
        // Range selection with Shift
        // Implementation depends on use case
      } else {
        // Toggle single item
        if (newSelected.has(itemId)) {
          newSelected.delete(itemId);
        } else {
          newSelected.add(itemId);
        }
      }
      onChange?.(Array.from(newSelected));
      return newSelected;
    });
  }, [onChange]);

  const selectAll = () => {
    const allIds = items.map(i => i.id);
    setSelected(new Set(allIds));
    onChange?.(allIds);
  };

  const clearAll = () => {
    setSelected(new Set());
    onChange?.([]);
  };

  const handleKeyDown = (e, index) => {
    switch (e.key) {
      case 'ArrowDown':
        e.preventDefault();
        setActiveIndex(Math.min(index + 1, items.length - 1));
        break;
      case 'ArrowUp':
        e.preventDefault();
        setActiveIndex(Math.max(index - 1, 0));
        break;
      case ' ':
        e.preventDefault();
        toggleSelection(items[index].id, e.shiftKey);
        break;
      case 'a':
        if (e.ctrlKey || e.metaKey) {
          e.preventDefault();
          selectAll();
        }
        break;
    }
  };

  return (
    <div className="multi-select">
      <div className="controls">
        <button onClick={selectAll}>Select All</button>
        <button onClick={clearAll}>Clear All</button>
        <span>{selected.size} of {items.length} selected</span>
      </div>
      
      <label id="listbox-label">{label}</label>
      <ul
        role="listbox"
        aria-labelledby="listbox-label"
        aria-multiselectable="true"
        tabIndex={0}
      >
        {items.map((item, index) => (
          <li
            key={item.id}
            role="option"
            aria-selected={selected.has(item.id)}
            tabIndex={index === activeIndex ? 0 : -1}
            onClick={(e) => toggleSelection(item.id, e.shiftKey)}
            onKeyDown={(e) => handleKeyDown(e, index)}
            className={selected.has(item.id) ? 'selected' : ''}
          >
            <span className="checkbox">
              {selected.has(item.id) ? 'β˜‘' : '☐'}
            </span>
            {item.label}
          </li>
        ))}
      </ul>
      
      {/* Announce selection changes */}
      <div role="status" aria-live="polite" className="sr-only">
        {selected.size} items selected
      </div>
    </div>
  );
}

// Usage
function App() {
  const languages = [
    { id: 'js', label: 'JavaScript' },
    { id: 'ts', label: 'TypeScript' },
    { id: 'py', label: 'Python' },
    { id: 'go', label: 'Go' },
    { id: 'rust', label: 'Rust' },
  ];

  return (
    <MultiSelectListbox
      items={languages}
      label="Select your favorite languages"
      initialSelected={['js', 'ts']}
      onChange={(selected) => console.log('Selected:', selected)}
    />
  );
}

Best Practices

βœ“

Set aria-multiselectable on the container (listbox, grid, tree), not on items

βœ“

Use aria-selected on each item to indicate its selection state

βœ“

Support keyboard shortcuts: Ctrl+Click, Shift+Click, Ctrl+A

βœ“

Provide "Select All" and "Clear" actions for convenience

βœ“

Announce selection count changes via aria-live regions

βœ“

Visually indicate multi-select capability (checkboxes, selection count)

Γ—

Don't put aria-multiselectable on individual itemsβ€”it goes on the container

Γ—

Don't use on tablists unless tabs can actually be multi-selected (rare)

Γ—

Don't forget to update aria-selected when selection changes

Common Use Cases

Tag/category selection
File browser with multi-select
Email list selection
Spreadsheet cell selection
Shopping cart item selection
User permission checkboxes
Multi-recipient selection
Filter option selection

Related Attributes

Specifications & Resources