# Manual Modality Testing Checklist

Four separate checklists for testing taga11y with different input modalities. Run all four before every release.

---

## Checklist 1: Keyboard-Only

Test all interactions using only the keyboard. No mouse, touch, or other pointer device.

### Setup
- Disable mouse/touch input if possible (or simply don't use the pointer)
- Use a page with a tagging input (e.g., `examples/basic-esm.html`)
- Ensure a visible focus indicator is present (check `--taga11y-color-border-focus`)

### Tab Order
- [ ] Press `Tab` from the previous page element — focus lands on the combobox input
- [ ] Press `Tab` while focus is on the combobox input — focus moves to the next page element (no trapping)
- [ ] Press `Shift+Tab` from the next page element — focus lands on the combobox input
- [ ] If chips exist, `Tab` cycles through: first chip remove button → subsequent remove buttons → combobox input → next page element

### Dropdown Interaction (Static/Pre-fetched Suggestions)
- [ ] Focus the combobox input — no dropdown opens on focus alone
- [ ] Press `ArrowDown` — dropdown opens, first suggestion is highlighted
- [ ] Press `ArrowDown` repeatedly — highlight moves through each suggestion with wrap-around (last → first)
- [ ] Press `ArrowUp` repeatedly — highlight moves upward with wrap-around (first → last)
- [ ] Press `Home` — highlight jumps to the first suggestion
- [ ] Press `End` — highlight jumps to the last suggestion
- [ ] Press `Enter` on a highlighted suggestion — suggestion is added as a tag, dropdown closes
- [ ] Type text, press `ArrowDown` — dropdown opens with filtered suggestions, first match highlighted
- [ ] Type text, press `Enter` without opening dropdown — text is committed as a tag (free mode)
- [ ] Press `Escape` — dropdown closes, input text is preserved, cursor position is preserved

### Dropdown Interaction (Dynamic Suggestions)
- [ ] Focus the combobox input — no dropdown opens on focus alone (dynamic mode requirement)
- [ ] Type text — after debounce delay, suggestions appear
- [ ] Navigate with arrow keys as above

### Chip Management
- [ ] Type text, press a delimiter key (comma by default) — text is committed as a tag, input clears, **dropdown closes** (if it was open)
- [ ] Type text, press `Enter` — text is committed as a tag, **dropdown closes**
- [ ] After any commit gesture closes the dropdown, type a character that matches a suggestion — dropdown re-opens via the normal filter flow
- [ ] With chips present, press `Backspace` on empty input — last chip is removed
- [ ] Press `Backspace` on non-empty input — character is deleted (browser handles)
- [ ] With chips present, press `Tab` (when Tab is a delimiter) — pending text is committed as a tag, focus moves out

### Whitelist Mode
- [ ] Type text that matches a suggestion, press `Enter` — tag is added
- [ ] Type text that does not match any suggestion, press `Enter` — error is shown ("Not in the list")
- [ ] Error region auto-dismisses after 2 seconds

### Max Tags
- [ ] Add tags until `maxTags` is reached
- [ ] Attempt to add another tag — error is shown ("Maximum tags reached")
- [ ] Remove a tag — ability to add another tag is restored

### Focus Indicator
- [ ] Focus ring is visible on the `.taga11y__tags` wrapper whenever the combobox input or a chip remove button has focus
- [ ] Focus ring is visible on chip remove buttons (in addition to the wrapper outline — the double indicator is intentional and communicates "you are inside the widget" + "specifically this button")
- [ ] Focus ring meets WCAG 2.2 focus appearance criteria (visible highlight, at least 3:1 contrast)

### Reduced Motion
- [ ] Enable `prefers-reduced-motion: reduce` in browser dev tools
- [ ] Loading spinner does not animate
- [ ] No transitions on chip add/remove
- [ ] No transitions on dropdown open/close
- [ ] No transitions on error region appear/dismiss

---

## Checklist 2: Touch / Pointer

Test all interactions using only a touch screen or mouse pointer.

### Setup
- Use a touch device or simulate touch in browser dev tools
- Use a page with a tagging input

### Chip Interaction
- [ ] Tap a chip remove button — tag is removed, focus returns to combobox input
- [ ] Tap a chip (not the remove button) — nothing happens (chips are not interactive beyond the remove button)
- [ ] Chip remove buttons have adequate hit targets (≥24x24 CSS px, 44x44 preferred) — implemented via a centered `::before` pseudo-element on `.taga11y__tag-remove`; verify by clicking a few px above/below the visible ✕ glyph
- [ ] Adjacent chips do not cause accidental taps on the wrong remove button

### Suggestion Interaction
- [ ] Open the dropdown (via keyboard or pointer)
- [ ] Tap a suggestion — tag is added, dropdown closes, input clears
- [ ] Tap outside the dropdown — dropdown closes
- [ ] Suggestion options are individually targetable with a pointer

### Input Interaction
- [ ] Tap the combobox input — input receives focus, cursor appears
- [ ] Type text via on-screen keyboard
- [ ] Delimiter keys work with on-screen keyboard input

### Multiple Tags
- [ ] Add multiple tags via suggestion taps
- [ ] Remove tags in any order via remove button taps
- [ ] Chip region scrolls if tags overflow (wrap to next line)

### Edge Cases
- [ ] Rapid taps on a remove button do not cause duplicate removals
- [ ] Tapping the input while a chip remove button is focused moves focus to the input
- [ ] Long-press on a chip does not trigger unexpected behavior (context menu, selection, etc.)

---

## Checklist 3: Voice Control

Test with voice control software (macOS Voice Control, Dragon NaturallySpeaking, or equivalent).

### Setup
- Enable voice control on your device
- Calibrate voice recognition if needed
- Use a page with a tagging input

### Focus
- [ ] Say the focus command for the combobox input — input receives focus
- [ ] Focus does not move unexpectedly when saying unrelated words

### Selecting Suggestions
- [ ] Say the label text of a suggestion (e.g., "JavaScript") — the suggestion is selected and added as a tag
- [ ] Say the label of a suggestion that is already added — error is shown ("Already added: JavaScript")
- [ ] Say the label of a suggestion not in the list (whitelist mode) — error is shown ("Not in the list")

### Removing Chips
- [ ] Say "Click Remove JavaScript" (or the exact aria-label of the remove button) — the tag is removed
- [ ] Say "Click Remove Go" — the Go tag is removed (not JavaScript)
- [ ] Chip remove buttons are individually targetable by their unique aria-label

### Typing and Committing
- [ ] Say text to type into the input, then say "Enter" — text is typed and committed as a tag
- [ ] Say text, then say a delimiter word (e.g., "comma") — text is committed and delimiter does not appear
- [ ] Say "Escape" — dropdown closes if open

### Navigation
- [ ] Say "Down arrow" repeatedly — highlight moves through suggestions
- [ ] Say "Up arrow" repeatedly — highlight moves upward
- [ ] Say "Home" — highlight jumps to first suggestion
- [ ] Say "End" — highlight jumps to last suggestion
- [ ] Say "Tab" — focus moves out of the component

### Edge Cases
- [ ] Saying a common word that matches multiple suggestions selects the first match
- [ ] Saying "Remove" without a specific label does not trigger any action
- [ ] Voice control can navigate to elements in logical order (no unexpected focus jumps)

---

## Checklist 4: Switch Device

Test with a single-switch scanning device (e.g., QuadSwitch, SwitchAccess on Android, or macOS Switch Control).

### Setup
- Enable switch device access on your device
- Configure a single input method (tap, head mouse, sip-and-puff, etc.)
- Use a page with a tagging input

### Scanning Order
- [ ] Scanning starts at the combobox input (first focusable element in the component)
- [ ] If chips exist, scanning continues through chip remove buttons in order
- [ ] After chips, scanning reaches the combobox input again (if not already selected)
- [ ] After the combobox input, scanning moves to the next page element (no trapping)
- [ ] Scanning direction is consistent and predictable (no jumps or reordering)

### Dropdown Scanning
- [ ] Open the dropdown (via switch activation on the input + Down arrow equivalent)
- [ ] Scanning enters the listbox and highlights suggestions one by one
- [ ] Each suggestion is individually selectable via switch activation
- [ ] After selecting a suggestion, scanning returns to the combobox input
- [ ] Closing the dropdown (via Escape equivalent) removes suggestions from the scan sequence

### Chip Removal
- [ ] Each chip remove button is individually reachable via scanning
- [ ] Activating a remove button removes the tag and returns focus to the combobox input
- [ ] After removal, the next chip in the scan sequence is the one that was previously after the removed chip

### No Focus Trapping
- [ ] Switching forward from the last element moves focus out of the component
- [ ] Switching backward from the first element moves focus to the previous page element
- [ ] No element is unreachable via the scan sequence

### Edge Cases
- [ ] Rapid scanning does not cause duplicate selections or removals
- [ ] Dropdown close does not cause scanning to skip elements
- [ ] Error messages do not interrupt the scan sequence (they are announced but do not capture focus)

---

## Checklist 5: Android Soft Keyboard (real-device required)

Soft keyboards on Android differ from desktop physical keyboards in two important ways: some wrap typing in continuous IME composition sessions for autocorrect, and some do not surface a usable `keydown.key` for delimiter taps. Both behaviours must be exercised on a real device or BrowserStack. jsdom and Playwright cannot reproduce true IME composition.

### Setup
- Real Android device or BrowserStack with Android.
- Chrome on Android, on a page with a tagging input that has a static suggestion list (e.g. `examples/basic-esm.html`).

### Gboard with autocorrect / prediction ON (canonical case — default Gboard install)
- [ ] Tap the combobox input, type "ap" — suggestion dropdown updates live per keystroke ("Apple" appears)
- [ ] Continue typing "app" — dropdown narrows live to "Apple"
- [ ] Add a space at the end — dropdown stays open (does not flash-close on the trailing space)
- [ ] Type "apple," — "apple" is committed as a tag, input clears, **dropdown closes**
- [ ] Paste a delimited list (e.g. "apple,banana,cherry") — three chips appear, input is empty, `taga11y:paste` fires with the three added tags, **dropdown closes** (does not auto-open to the remaining suggestion list)
- [ ] After any commit gesture closes the dropdown, type a matching character — dropdown re-opens via the normal filter flow
- [ ] **Dynamic suggestions tap-mid-debounce** (use `examples/dynamic.html`): type a partial query, wait for results, then tap a result before pausing to let the next debounce fire — chip is added, dropdown stays closed, does not flash open after the debounce timer elapses
- [ ] **Press-and-hold an option** — highlight appears under the finger while held, clears on lift. Releasing on an option commits; releasing off-target commits nothing. At any moment at most one option is visually highlighted at rest (only the keyboard-style `aria-activedescendant` highlight)
- [ ] **Backspace on empty input with at least one chip — chip is NOT removed.** Known platform limitation: Gboard dispatches no event (keydown/beforeinput/input) when the input is empty. Use the chip's ✕ remove button instead. See `docs/guides/limitations.md`.

### Gboard with autocorrect / prediction OFF (control)
- [ ] Same expectations as above hold, including the Gboard backspace-on-empty limitation

### FUTO keyboard (control + delimiter fix verification)
- [ ] Type "ap" — dropdown updates live per keystroke
- [ ] **Type "test," — "test" is committed as a tag.** FUTO autospaces after punctuation, so a single comma tap inserts `", "` (comma + space) as one `input` event; `input.value` becomes `"test, "`. Verify the commit fires despite the trailing space. (Was a regression: trailing whitespace after the delimiter previously blocked the commit.)
- [ ] Type "apple," — "apple" is committed as a tag (verifies the input-event delimiter path; FUTO does not surface `keydown.key === ','`), **dropdown closes**
- [ ] Paste a delimited list — three chips appear, `taga11y:paste` fires, **dropdown closes**
- [ ] **Dynamic suggestions tap-mid-debounce**: same as Gboard above — tapping an option before the next debounce fires must not reopen the listbox
- [ ] **Press-and-hold an option**: highlight tracks the finger, clears on lift, only one option highlighted at rest

### iOS Safari (sanity check, not gating)
- [ ] Type a word with autocorrect on — dropdown updates live per keystroke; autocorrect commits do not collapse the dropdown unexpectedly

### Trade-offs to be aware of
- True CJK IME users (Japanese, Korean, Chinese) on any platform will see suggestions filter against the intermediate composition string. This matches `<datalist>` behaviour and is the accepted trade-off — confirm this is non-disruptive on a CJK keyboard if available.
