refactor(document-picker): downgrade listbox ARIA roles; fix unique listboxId

role=listbox + role=option without arrow-key navigation is misleading — the
WAI-ARIA combobox pattern requires aria-activedescendant handling that isn't
implemented. Downgraded to plain <ul>/<li>; input keeps role=combobox +
aria-controls pointing to the list id.

listboxId was a module-level constant so two simultaneous instances would share
the same DOM id. Fixed with a <script module> counter.

Updated spec queries from getByRole('option') to getByText() — tests behaviour,
not the ARIA implementation.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Marcel
2026-06-09 18:59:30 +02:00
parent 7df640201a
commit d35a165881
2 changed files with 13 additions and 10 deletions

View File

@@ -1,3 +1,7 @@
<script module>
let _uid = 0;
</script>
<script lang="ts">
import { m } from '$lib/paraglide/messages.js';
import { clickOutside } from '$lib/shared/actions/clickOutside';
@@ -19,7 +23,7 @@ let {
onSelect
}: Props = $props();
const listboxId = 'doc-picker-listbox';
const listboxId = `doc-picker-listbox-${++_uid}`;
const picker = createDocumentTypeahead();
@@ -61,7 +65,6 @@ function handleSelect(doc: DocumentOption) {
{#if picker.isOpen && (picker.results.length > 0 || picker.loading)}
<ul
id={listboxId}
role="listbox"
class="ring-opacity-5 absolute z-50 mt-1 max-h-60 w-full overflow-auto rounded-md bg-surface py-1 text-sm shadow-lg ring-1 ring-black"
>
{#if picker.loading}
@@ -70,8 +73,6 @@ function handleSelect(doc: DocumentOption) {
{#each picker.results as doc (doc.id)}
{@const disabled = alreadyAddedIds.has(doc.id!)}
<li
role="option"
aria-selected={false}
aria-disabled={disabled}
onclick={() => handleSelect(doc)}
onkeydown={(e) => e.key === 'Enter' && handleSelect(doc)}