agentsclimarketplace

A11y listbox

Skill xrnavigation/web-a11y-plugin/skills/a11y-listbox

Web accessibility agent skills — 23 cite-backed skills covering APG widget patterns, audit tooling, ARIA guidance, cognitive accessibility, and more. Works with Claude Code, Codex CLI, and Gemini CLI.

Install
npx -y skills add xrnavigation/web-a11y-plugin --skill a11y-listbox

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Guides accessible listbox implementation for single and multi-select lists per APG patterns. Auto-invokes when creating listboxes, selection lists, option lists, or custom multi-select components. Covers required ARIA, keyboard interaction, single vs multi-select, and reorderable lists (WCAG 2.2 dragging alternatives).

SKILL.md

10.3 KB, as published. Nobody here has run it

Accessible Listbox Implementation

"It is highly recommended using the HTML select element... because there is a lot of keyboard interactivity to manage focus for all the descendants, and native HTML elements provide this functionality for you for free." — MDN: ARIA listbox role

A listbox presents a list of options and allows the user to select one or more. Every ARIA listbox you build is a promise to implement all keyboard interaction, focus management, and state updates yourself. Native <select> does this for free.


1. Decision: Native <select> vs ARIA Listbox

Use native <select> by default

Native <select> scored 100% success rate and 97.5% usability across all screen readers tested (24a11y, "Select Your Poison Part 2"). Custom ARIA implementations consistently scored lower.

Use ARIA listbox only when

  • Options must contain images or complex content that <select> cannot render (APG Listbox Pattern)
  • A dual-listbox transfer pattern or other composite widget is required
  • Custom scrollable lists with non-text layouts are needed

Use combobox pattern instead when

  • The dropdown needs filtering/autocomplete — see a11y-combobox skill
  • You need a custom-styled single-select that collapses to a button — use the APG select-only combobox, not a standalone listbox

Use checkboxes/radio buttons when

  • Single-select with few options: radio button group
  • Multi-select with few options: checkbox group

These outperform custom multi-select for usability (MDN; 24a11y).


2. Required ARIA Structure

Single-select listbox

<label id="color-label">Favorite color</label>
<ul role="listbox"
    tabindex="0"
    aria-labelledby="color-label">
  <li role="option" id="opt-red" aria-selected="true">Red</li>
  <li role="option" id="opt-blue" aria-selected="false">Blue</li>
  <li role="option" id="opt-green" aria-selected="false">Green</li>
</ul>

Multi-select listbox

<label id="toppings-label">Toppings</label>
<ul role="listbox"
    tabindex="0"
    aria-labelledby="toppings-label"
    aria-multiselectable="true">
  <li role="option" id="top-cheese" aria-selected="true">Cheese</li>
  <li role="option" id="top-peppers" aria-selected="false">Peppers</li>
  <li role="option" id="top-onions" aria-selected="false">Onions</li>
</ul>

Required attributes summary

ComponentAttributeWhen
Containerrole="listbox"Always
Containertabindex="0"Always
Containeraria-labelledby or aria-labelAlways
Containeraria-multiselectable="true"Multi-select only
Containeraria-orientation="horizontal"Horizontal layout only (default is vertical)
Containeraria-activedescendantWhen using activedescendant focus management
Optionrole="option"Always
Optionaria-selectedAlways — every option needs true or false
Grouprole="group" + aria-labelWhen grouping options
Virtualizedaria-setsize + aria-posinsetWhen not all options are in the DOM

(APG Listbox Pattern; WAI-ARIA 1.2)


3. Single vs Multi-select

The architectural difference: in single-select, selection may follow focus (arrow keys both move focus and change selection). In multi-select, focus and selection are decoupled — moving focus must not change existing selections (APG Listbox Pattern).

// WRONG — selection follows focus in multi-select
function onArrowDown(listbox) {
  focusNext();
  if (listbox.getAttribute('aria-multiselectable') === 'true') {
    selectFocused(); // Destroys existing selections!
  }
}

// RIGHT — decouple focus from selection in multi-select
function onArrowDown(listbox) {
  focusNext();
  // In multi-select: focus moves, selection unchanged
  // User must press Space to toggle selection
}

Focus landing behavior

  • Single-select: Focus pre-selected option, or first option (which may auto-select)
  • Multi-select: Focus first selected option, or first option. Never auto-select on focus.

(APG Listbox Pattern)


4. Keyboard Interaction Summary

All listboxes

KeyBehavior
Down ArrowMove focus to next option
Up ArrowMove focus to previous option
HomeFocus first option (recommended for 5+ options)
EndFocus last option (recommended for 5+ options)
Type-aheadFocus matching option (recommended for 7+ options)

Single-select additions

KeyBehavior
SpaceSelect focused option
Down/Up ArrowMay also select (selection follows focus)

Multi-select additions (recommended model)

KeyBehavior
SpaceToggle selection of focused option
Shift + Down/UpMove focus and toggle selection
Shift + SpaceSelect contiguous range
Ctrl + ASelect/deselect all

For the complete keyboard spec including the alternative modifier-key model, see ${CLAUDE_SKILL_DIR}/references/keyboard-interaction.md.


5. Reorderable Lists (WCAG 2.2)

WCAG 2.5.7 Dragging Movements (Level AA) requires that all drag-and-drop functionality provide a single-pointer alternative that does not require dragging (WCAG 2.2 SC 2.5.7).

A keyboard alternative alone is insufficient — touch-screen users may not have a physical keyboard. You must provide both:

  1. Keyboard reordering: e.g., Alt + Arrow keys to move selected item
  2. Pointer-based non-drag alternative: visible up/down buttons, "move to position" menu, or numeric input

Compliant alternatives

<!-- RIGHT — visible move buttons satisfy SC 2.5.7 -->
<li role="option" aria-selected="true">
  Item A
  <button aria-label="Move Item A up">Up</button>
  <button aria-label="Move Item A down">Down</button>
</li>

Note: The move buttons must be outside the role="option" element — interactive elements inside options are not valid. Use the Grid pattern if options need interactive children (APG Listbox Pattern).

(W3C Technique G219; Sparkbox)


6. Common Mistakes

6.1 Using ARIA listbox when native <select> suffices

<!-- WRONG — unnecessary complexity -->
<div role="listbox" tabindex="0">
  <div role="option">Option 1</div>
</div>

<!-- RIGHT — native element, zero ARIA needed -->
<select>
  <option>Option 1</option>
</select>

Native elements get keyboard interaction for free (MDN; APG).

6.2 Missing aria-selected on options in multi-select

<!-- WRONG — VoiceOver refuses to read options without explicit state -->
<ul role="listbox" aria-multiselectable="true">
  <li role="option">Cheese</li>
  <li role="option" aria-selected="true">Peppers</li>
</ul>

<!-- RIGHT — every option declares its selection state -->
<ul role="listbox" aria-multiselectable="true">
  <li role="option" aria-selected="false">Cheese</li>
  <li role="option" aria-selected="true">Peppers</li>
</ul>

When aria-multiselectable="true" is set, every option must have explicit aria-selected (MDN).

6.3 Interactive elements inside options

<!-- WRONG — links/buttons inside role="option" are not valid -->
<li role="option">
  <a href="/details">Item A</a>
  <button>Remove</button>
</li>

<!-- RIGHT — use Grid pattern for interactive children -->
<div role="grid">
  <div role="row">
    <div role="gridcell"><a href="/details">Item A</a></div>
    <div role="gridcell"><button>Remove</button></div>
  </div>
</div>

(APG Listbox Pattern)

6.4 Missing aria-orientation on horizontal listboxes

The implicit orientation is vertical. Horizontal layouts must set aria-orientation="horizontal" explicitly, or arrow key expectations will be wrong (WAI-ARIA 1.2).

6.5 No visible focus indicator

The focused option must have a visible focus ring or highlight. Without it, sighted keyboard users cannot orient (WCAG 2.4.7).

6.6 Not scrolling focused option into view

In scrollable listboxes, programmatic scroll-into-view on focus change is required. Without it, the focused option becomes invisible to sighted users.


7. Cross-References

  • aria-decision-framework — decide whether you need ARIA at all (start here)
  • a11y-combobox — for filterable/autocomplete dropdowns and styled select replacements

For detailed reference material:

  • ${CLAUDE_SKILL_DIR}/references/keyboard-interaction.md — complete keyboard spec for both multi-select models
  • ${CLAUDE_SKILL_DIR}/references/common-mistakes.md — expanded mistake catalog with screen reader details
  • ${CLAUDE_SKILL_DIR}/references/screen-reader-behavior.md — JAWS, NVDA, VoiceOver behavior notes
  • ${CLAUDE_SKILL_DIR}/references/sources.yaml — provenance for all cited sources

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.