Skip to content

feat: disabled options + required validation + Tier 3 polish (v3.3.0) - #4

Merged
michaeljfalk merged 1 commit into
mainfrom
feat/3.3.0-options-validation-polish
Jun 17, 2026
Merged

michaeljfalk merged 1 commit into
mainfrom
feat/3.3.0-options-validation-polish

Conversation

@michaeljfalk

Copy link
Copy Markdown
Owner

Summary

Tier 2 (minus multi-select) + all four Tier 3 polish items from the roadmap. All additive, no breaking changes.

Disabled options

  • Per-option disabled: true → non-selectable: dimmed, aria-disabled, skipped by ↑/↓ nav, ignored on click/Enter.

required form validation

  • Enforced via the Constraint Validation API on the visible input, so an empty required control blocks form submit with a focusable, on-screen bubble (message via texts.required).
  • Fixes enhance(): a display:none required <select> can't be focused (browsers reject submit with "invalid form control is not focusable"); enforcement now lives on the visible control.

Match highlighting

  • highlight: true wraps the matched substring in <mark class="liveselect__mark">, built from text nodes (no innerHTML) so it stays XSS-safe. Ignored for renderOption rows.

"Showing N of M" footer

  • Array sources compute the total automatically; async sources may return { items, total }. Customize via texts.more(shown, total).

Lifecycle events

  • Bubbling liveselect:open, liveselect:close, liveselect:search ({ query }), alongside liveselect:change.

Async result caching

  • cache: true memoizes async results by query+scope+limit; cleared by setSource() / setScope().

Changes

  • dist/liveselect.js — disabled in normalizeOption; _step/_isEnabled keyboard skip; _syncValidity; _highlightInto; _total + cache in _runSearch; _dispatch + open/close/search events; "more" footer in _renderMenu
  • dist/liveselect.css — __opt--disabled, __mark (+ dark), __more
  • test/client.test.js — 6 new tests → 36/36 pass
  • README.md — options table, option shape, async-ctx, Events table, Validation section, Features bullet
  • examples/vanilla.html — picker 1 now uses highlight + a disabled row
  • CHANGELOG.md + package.json — bump to 3.3.0

Test plan

  • npm test → 36/36 (was 30); existing XSS/escaping/a11y regressions still pass
  • Core + example inline script parse clean

🤖 Generated with Claude Code

Tier 2 (minus multi-select) plus all Tier 3 polish from the roadmap:

- Disabled options: per-option `disabled: true` → non-selectable (dimmed,
  aria-disabled, skipped by keyboard nav, ignored on click/Enter).
- Required validation: enforced via the Constraint Validation API on the
  visible input, so an empty required control blocks submit with a focusable,
  on-screen bubble. Makes enhance()'s required actually enforce (a display:none
  <select> can't be focused). Message via texts.required.
- Match highlighting: `highlight: true` wraps the matched substring in <mark>
  (built from text nodes → still XSS-safe). Ignored for renderOption rows.
- "Showing N of M" footer: array sources compute total; async sources may
  return { items, total }. Customize via texts.more(shown, total).
- Lifecycle events: bubbling liveselect:open / liveselect:close /
  liveselect:search ({ query }).
- Async result caching: `cache: true` keys by query+scope+limit; cleared by
  setSource()/setScope().

6 new jsdom tests (36 total), CSS for disabled/mark/more + dark-mode mark,
README (options table, Events table, Validation section, Features bullet),
example updated (highlight + a disabled row), CHANGELOG/version bump to 3.3.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@michaeljfalk
michaeljfalk merged commit 4f6ee40 into main Jun 17, 2026
5 checks passed
@michaeljfalk
michaeljfalk deleted the feat/3.3.0-options-validation-polish branch June 17, 2026 18:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant