Composer "Aan": replace the hand-rolled combobox with nldd-combo-box #209

Closed
opened 2026-07-27 04:32:27 +00:00 by robbertbos · 1 comment
Owner

frontend/src/components/composer/TargetPicker.vue is a ~480-line hand-rolled combobox for the new-message "Aan" field: a native <input role="combobox"> with aria-activedescendant, a role="listbox" popup, a polite live region, full ArrowUp/Down/Home/End/Enter/Escape keyboard handling and ~150 lines of NLDD-token CSS. Its header comment even states "There is no NLDD combobox" - that is no longer true.

NLDD 0.8.69 ships nldd-combo-box (dist/components/inputs/combo-box/) plus the list / list-item cell components. Adopting it removes the bespoke ARIA, keyboard wiring and CSS, and gives us the design system's built-in accessibility and focus behaviour for free ("componeer, herstijl niet").

Scope

  • Replace the custom input + listbox + option markup with nldd-combo-box (with nldd-list / cells as the option template).
  • Drop the bespoke keyboard handler, aria-activedescendant bookkeeping, live region and the .listbox / .option / .input CSS.
  • Preserve current behaviour:
    • account-scoped targets (useTargets); collapse to a removable chip on select;
    • token match across channel name AND team name (matchesTokens, so "off topic groep x" narrows on both);
    • =2-char debounced people search (usePeopleSearch) to start a new DM, deduped against targets already reachable;

    • the focus() method the overlay calls on open;
    • the per-option icon and subtitle (iconFor / subtitleFor).

Verify

  • Keyboard: open, arrow-navigate, Enter selects, Escape closes, chip-remove returns focus.
  • Existing composer unit/e2e behaviour still holds.

Relates to #195 (composer refinement + NLDD alignment) and #182 (align custom popovers to NLDD).

`frontend/src/components/composer/TargetPicker.vue` is a ~480-line hand-rolled combobox for the new-message "Aan" field: a native `<input role="combobox">` with `aria-activedescendant`, a `role="listbox"` popup, a polite live region, full ArrowUp/Down/Home/End/Enter/Escape keyboard handling and ~150 lines of NLDD-token CSS. Its header comment even states "There is no NLDD combobox" - that is no longer true. NLDD 0.8.69 ships `nldd-combo-box` (`dist/components/inputs/combo-box/`) plus the list / list-item cell components. Adopting it removes the bespoke ARIA, keyboard wiring and CSS, and gives us the design system's built-in accessibility and focus behaviour for free ("componeer, herstijl niet"). ## Scope - Replace the custom input + listbox + option markup with `nldd-combo-box` (with `nldd-list` / cells as the option template). - Drop the bespoke keyboard handler, `aria-activedescendant` bookkeeping, live region and the `.listbox` / `.option` / `.input` CSS. - Preserve current behaviour: - account-scoped targets (`useTargets`); collapse to a removable chip on select; - token match across channel name AND team name (`matchesTokens`, so "off topic groep x" narrows on both); - >=2-char debounced people search (`usePeopleSearch`) to start a new DM, deduped against targets already reachable; - the `focus()` method the overlay calls on open; - the per-option icon and subtitle (`iconFor` / `subtitleFor`). ## Verify - Keyboard: open, arrow-navigate, Enter selects, Escape closes, chip-remove returns focus. - Existing composer unit/e2e behaviour still holds. Relates to #195 (composer refinement + NLDD alignment) and #182 (align custom popovers to NLDD).
Author
Owner

Investigated adopting nldd-combo-box (NLDD 0.8.69). Two capability gaps make it a poor fit here:

  1. nldd-menu-item is text + icon only (no subtitle / supporting-text), so the per-option second line - team name for channels, @username / "Nieuw direct bericht" for people - cannot render. That line disambiguates same-named channels across teams and is what makes the picker usable.
  2. The selection would show as text in the combobox input with a clear button, not the current removable chip.

Decision: keep TargetPicker (the two-line + chip UX is better) and rescope this ticket to aligning its internals to NLDD tokens/components without changing the UX. First pass in this PR: remove button -> nldd-icon-button; focus ring -> the shared NLDD focus-ring tokens (via the global :focus-visible); dropdown shadow -> --semantics-overlays-box-shadow (it was falling back to a hardcoded value since --shadow-md was retired).

For the record: nldd-menu does expose a custom filterFn and nldd-menu-item has an aliases search field, so the token x (channel|team) matching would have been preservable; the blocker is purely the missing subtitle + the chip.

Investigated adopting nldd-combo-box (NLDD 0.8.69). Two capability gaps make it a poor fit here: 1. `nldd-menu-item` is text + icon only (no subtitle / supporting-text), so the per-option second line - team name for channels, `@username` / "Nieuw direct bericht" for people - cannot render. That line disambiguates same-named channels across teams and is what makes the picker usable. 2. The selection would show as text in the combobox input with a clear button, not the current removable chip. Decision: keep TargetPicker (the two-line + chip UX is better) and rescope this ticket to aligning its internals to NLDD tokens/components without changing the UX. First pass in this PR: remove button -> `nldd-icon-button`; focus ring -> the shared NLDD focus-ring tokens (via the global `:focus-visible`); dropdown shadow -> `--semantics-overlays-box-shadow` (it was falling back to a hardcoded value since `--shadow-md` was retired). For the record: `nldd-menu` does expose a custom `filterFn` and `nldd-menu-item` has an `aliases` search field, so the token x (channel|team) matching would have been preservable; the blocker is purely the missing subtitle + the chip.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
robbertbos/waggle#209
No description provided.