j3w1 / theme

j3w1 / theme4.0.0

j3w1 / command

  • SPEC Overview
  • SPEC Foundations
  • SPEC Components
  • SPEC Patterns
  • SPEC Tokens
  • SPEC Tools
  • SPEC Workbench
  • SPEC Form builder
  • SPEC Task kit
  • SPEC Recipes
  • SPEC Figma bridge
  • SPEC Report an issue
  • SPEC Implement
  • SPEC For agents
  • SPEC Ports
  • SPEC Releases
  • SPEC Specification
  • DEMO Vue application demo

Select

A themed single-choice combobox or multiple-choice list backed by a native select for forms and the no-JavaScript fallback.

stable · light DOM · 4.0.0. Theme-owned combobox/listbox presentation backed by the original native select for FormData, constraints, defaults and reset. The native control is visible only before enhancement or without JavaScript.

Live variants

default

New windows open here.

✕ Choose a workspace.

Markup
<j3w1-select id="example-select-default"><div class="select">
  <label class="select-label" for="example-select-default-sel-workspace">Workspace <span class="select-required" aria-hidden="true">*</span><span class="select-required sr-only"> required</span></label>
  <div class="select-root">
    <select class="select-control" id="example-select-default-sel-workspace" aria-describedby="example-select-default-sel-workspace-help example-select-default-sel-workspace-message" name="example-select-default-sel-workspace">
      <option value="">Choose a workspace</option>
      <option value="1" selected="">1: terminal</option>
      <option value="2">2: editor</option>
      <option value="3">3: browser</option>
    </select>
    <svg class="select-chevron" aria-hidden="true" focusable="false" width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="square"><path d="M4 6.5l4 4 4-4"></path></svg>
  </div>
  <p class="select-help" id="example-select-default-sel-workspace-help">New windows open here.</p>
  <p class="select-message" id="example-select-default-sel-workspace-message">✕ Choose a workspace.</p>
</div></j3w1-select>

with-groups

Fallbacks use recorded size-adjust metrics.

✕ That font is not installed.

Markup
<j3w1-select id="example-select-with-groups"><div class="select">
  <label class="select-label" for="example-select-with-groups-sel-font">Font <span class="select-required" aria-hidden="true">*</span><span class="select-required sr-only"> required</span></label>
  <div class="select-root">
    <select class="select-control" id="example-select-with-groups-sel-font" aria-describedby="example-select-with-groups-sel-font-help example-select-with-groups-sel-font-message" name="example-select-with-groups-sel-font">
      <optgroup label="Installed">
        <option value="scp" selected="">SauceCodePro NFM</option>
        <option value="cascadia">Cascadia Mono</option>
      </optgroup>
      <optgroup label="Fallbacks">
        <option value="consolas">Consolas</option>
        <option value="dejavu">DejaVu Sans Mono</option>
      </optgroup>
    </select>
    <svg class="select-chevron" aria-hidden="true" focusable="false" width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="square"><path d="M4 6.5l4 4 4-4"></path></svg>
  </div>
  <p class="select-help" id="example-select-with-groups-sel-font-help">Fallbacks use recorded size-adjust metrics.</p>
  <p class="select-message" id="example-select-with-groups-sel-font-message">✕ That font is not installed.</p>
</div></j3w1-select>

multiple

Click or Space toggles an option; Shift+arrows selects a range. The native fallback uses Ctrl/Command+click.

✕ Choose at least one output.

Markup
<j3w1-select id="example-select-multiple"><div class="select">
  <label class="select-label" for="example-select-multiple-sel-outputs">Outputs <span class="select-required" aria-hidden="true">*</span><span class="select-required sr-only"> required</span></label>
  <div class="select-root">
    <select class="select-control select-control-multiple" id="example-select-multiple-sel-outputs" multiple="" size="4" aria-describedby="example-select-multiple-sel-outputs-help example-select-multiple-sel-outputs-message" name="example-select-multiple-sel-outputs">
      <option value="dp1" selected="">DP-1 (2560×1440)</option>
      <option value="dp2" selected="">DP-2 (2560×1440)</option>
      <option value="hdmi">HDMI-1 (1920×1080)</option>
      <option value="edp">eDP-1 (laptop)</option>
    </select>
  </div>
  <p class="select-help" id="example-select-multiple-sel-outputs-help">Click or Space toggles an option; Shift+arrows selects a range. The native fallback uses Ctrl/Command+click.</p>
  <p class="select-message" id="example-select-multiple-sel-outputs-message">✕ Choose at least one output.</p>
</div></j3w1-select>

Install and register

Use the exact version. If npm publication is pending, install the release tarball from the installation guide.

npm install --save-exact @j3w1/ui@4.0.0
import '@j3w1/ui/tokens.css';
import '@j3w1/ui/styles/select.css';
import '@j3w1/ui/register/select';

Insert the maintained markup above after loading these imports. Its native children provide accessible names and form behavior; the empty custom tag alone does not create a control.

Vue SFC, React, Astro and plain HTML integration →

Copy the complete implementation

npx --package=@j3w1/ui@4.0.0 j3w1-ui copy select --out ./vendor/j3w1/select

The CLI verifies every file before writing and refuses overwrites. Serve the output over HTTP and open index.html. Keep its modules, CSS, tokens and licence notices together.

Public API

attributes

NameType / signatureMeaning
disabledCustomEventDisable the native controls owned by this instance.
loadingCustomEventMark the primary control busy and prevent duplicate activation.
valueCustomEventForwards value to the primary native control.
requiredCustomEventForwards required to the primary native control.
readonlyCustomEventForwards readonly to the primary native control.
checkedCustomEventForwards checked to the primary native control.

properties

NameType / signatureMeaning
disabledbooleanDelegates disabled state to native children.
namestringNative control name; application form keys remain explicit.
valuestringPrimary native value; assignment does not fabricate user events.
checkedbooleanNative checkbox state.
requiredbooleanNative required constraint.
readOnlybooleanNative readonly property.
formHTMLFormElement | nullOwning native form. Read only.
valuesstring[]Selected values of a multiple native select.

methods

NameType / signatureMeaning
refresh(): voidReconnect behavior after replacing native child structure.
focus(options?: FocusOptions): voidFocus the first usable native control.
checkValidity(): booleanCheck owned native constraints.
reportValidity(): booleanReport the first invalid owned control.
clear(): voidClear an editable primary input and emit native input/change.

events

NameType / signatureMeaning
j3w1-changeCustomEventNative change from an owned control, alongside the original native event.

Dependencies and verification

Registered components: none. Style dependencies: none.

Package presence establishes an available implementation. Actual passes depend on the tested artifact and environment. Read specification execution evidence; read packed-consumer evidence; inspect the complete state matrix.

Full implementation manifest, API and token dependency closure

Canonical specification

Select select

  • Family: Basic forms
  • Maturity: stable
  • Priority: R1
  • Since: 0.1.0
  • Custom widget: Select-only combobox with listbox popup; multiple variant is a multiselectable listbox — APG pattern
  • specified
  • demonstrated
  • test implemented

A themed single-choice combobox or multiple-choice list backed by a native select for forms and the no-JavaScript fallback.

Report an issue with this component

Tokens

Focus a role to inspect its values; follow its link for persistent usage and source details.

PartRoleValueUse
root.bgcolor.surface.inputapproveduse#000000Form-control fill.
root.bordercolor.border.controlapproveduse#c81a1aD-041 owner correction: red control and floating-frame borders, distinct from rose text.
root.bg-hovercolor.interaction.hover.bgapproveduse#1c1010D-041 interaction.hover.bg: color.primitive.modern.hover.
root.border-focuscolor.border.activeobserveduse#e53935Active or focused control border.
root.ringcolor.interaction.focus.ringobserveduse#e539351px dashed focus ring on controls and rows.
root.ring-invalidcolor.interaction.focus.ring-containerobserveduse#ffa2a7Focus colour for containers and explicitly mapped filled controls (D-015); component rules determine ring geometry.
root.border-invalidcolor.status.danger.borderobserveduse#e53935Danger border, 2px on invalid inputs.
root.border-disabledcolor.border.disabledapproveduse#482b2bD-041 border.disabled: color.primitive.modern.divider.
root.bg-disabledcolor.interaction.disabled.bgapproveduse#0d0707D-041 interaction.disabled.bg: color.primitive.modern.panel.
control.textcolor.text.defaultapproveduse#e99499D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.
control.text-disabledcolor.text.disabledapproveduse#a3676bD-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.
chevron.strokecolor.icon.defaultapproveduse#e99499D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.
option.bgcolor.surface.raisedapproveduse#140b0bD-041 surface.raised: color.primitive.modern.raised.
option.textcolor.text.defaultapproveduse#e99499D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.
option.bg-selectedcolor.interaction.selection.bgapproveduse#531310Selected row, tab, workspace; D-027 recessed the fill, leaving the 2px indicator and the check to carry selection.
option.text-selectedcolor.interaction.selection.textobserveduse#f4eeeeText on the selection.
group.textcolor.text.mutedapproveduse#d4868bD-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.
label.textcolor.text.brightapproveduse#ffa2a7D-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.
label.required-markcolor.status.danger.textobserveduse#f07178D-041 readable error text on neutral surfaces and native warning tints.
help.textcolor.text.mutedapproveduse#d4868bD-041 owner correction: rose is the default UI and reading foreground; near-white is reserved for document headings, highlights and contrast-critical fills.
message.textcolor.status.danger.textobserveduse#f07178D-041 readable error text on neutral surfaces and native warning tints.

State matrix

Every declared state and combination, statically rendered; the default cell is live. Sizes: compact, comfortable (switch with the density control above).

StateSingleWith option groupsMultiple
default

New windows open here.

✕ Choose a workspace.

Fallbacks use recorded size-adjust metrics.

✕ That font is not installed.

Click or Space toggles an option; Shift+arrows selects a range. The native fallback uses Ctrl/Command+click.

✕ Choose at least one output.

hover
focus-visible
required
invalid
invalid+focus-visible
disabled

Purpose

One or several options from a fixed list. D-025 requires theme-owned choice surfaces in web applications; the native select stays the form-value and constraint source. A searchable or asynchronous list is combobox.

Anatomy

Each selected option has a check mark and the selection fill. The hidden native <select> keeps its name, options, current values and defaults.

States

StateVisualNon-colour channel
default1px color.border.control on color.surface.input; value color.text.default; chevron color.icon.defaultthe chevron
hoverbackground → color.interaction.hover.bg; border unchangedcursor: default; hover-capable pointers only
focus-visibleborder → color.border.active; 1px dashed color.interaction.focus.ring at −2pxthe ring
required* after the label in color.status.danger.text plus visually hidden “required”required; the mark
invalid2px color.status.danger.border; message with ✕border 1 → 2px; glyph; aria-invalid
invalid+focus-visible2px danger border and color.interaction.focus.ring-container ring at −4pxdouble boundary
disabledtext and chevron color.text.disabled; color.border.disabled; color.interaction.disabled.bgdisabled; cursor: not-allowed

In the list, a selected option is color.interaction.selection.bg with color.interaction.selection.text; group labels color.text.muted on color.surface.raised. Precedence: disabled > invalid > hover; focus-visible is always drawn.

Keyboard

As in the key table, plus Home/End to the ends of the single list. Ordinary multiple selection needs no modifier. The native fallback keeps host behaviour.

Accessibility

A programmatic label is required. The first option is a real choice or a disabled selected placeholder with text (“Choose a workspace”), never empty. aria-invalid="true" only after interaction or submit. The visible control carries the label, required and invalid state, and descriptions (help and message via aria-describedby). A failed native constraint focuses the visible control and shows a theme-owned error. Disabled options, optgroups and fieldsets stay unavailable. Values and defaults survive reconnection, programmatic updates and form reset. Automated evidence records its real environments and implies no manual screen-reader pass.

Portability

Web implementations use the packaged behaviour and its complete copy closure. The enhancement can apply the same renderer to existing selects without moving them or duplicating form values.

Non-examples

An unthemed browser popup presented as fully themed. A background-image chevron in a literal colour. Rounded corners. A blank first option. Navigation on change. Invalid by colour alone. A glow instead of the ring. Disabling by opacity.

Contrast report

22 declared pairs measured on resolved sRGB values with the WCAG 2.x formula; 0 waived (decorative only), 0 failing. A pass is a design target for the named role, not an application-wide conformance claim.

PairStateKindForegroundBackgroundRatioMinResult
select default textdefaulttextcolor.text.default #e99499color.surface.input #0000009.164.5pass
select default borderdefaultuicolor.border.control #c81a1acolor.surface.input #0000003.623pass
select hover texthovertextcolor.text.default #e99499color.interaction.hover.bg #1c10108.104.5pass
select hover borderhoveruicolor.border.control #c81a1acolor.interaction.hover.bg #1c10103.203pass
select focus-visible textfocus-visibletextcolor.text.default #e99499color.surface.input #0000009.164.5pass
select focus-visible borderfocus-visibleuicolor.border.active #e53935color.surface.input #0000004.973pass
select focus-visible outlinefocus-visibleuicolor.interaction.focus.ring #e53935color.surface.input #0000004.973pass
select required textrequiredtextcolor.text.default #e99499color.surface.input #0000009.164.5pass
select required borderrequireduicolor.border.control #c81a1acolor.surface.input #0000003.623pass
select invalid textinvalidtextcolor.text.default #e99499color.surface.input #0000009.164.5pass
select invalid borderinvaliduicolor.status.danger.border #e53935color.surface.input #0000004.973pass
select invalid+focus-visible textinvalid+focus-visibletextcolor.text.default #e99499color.surface.input #0000009.164.5pass
select invalid+focus-visible borderinvalid+focus-visibleuicolor.status.danger.border #e53935color.surface.input #0000004.973pass
select invalid+focus-visible outlineinvalid+focus-visibleuicolor.interaction.focus.ring-container #ffa2a7color.surface.input #00000010.983pass
chevron on the input surface—uicolor.icon.default #e99499color.surface.input #0000009.163pass
option text in the themed list—textcolor.text.default #e99499color.surface.raised #140b0b8.464.5pass
group label in the themed list—textcolor.text.muted #d4868bcolor.surface.raised #140b0b7.014.5pass
selected option—textcolor.interaction.selection.text #f4eeeecolor.interaction.selection.bg #53131012.474.5pass
validation message on the panel surface—textcolor.status.danger.text #f07178color.surface.default #0d07076.984.5pass
help text on the panel surface—textcolor.text.muted #d4868bcolor.surface.default #0d07077.224.5pass
disabled text (exempt; house floor 3:1)disableduicolor.text.disabled #a3676bcolor.interaction.disabled.bg #0d07074.483pass
disabled border (exempt)disableduicolor.border.disabled #482b2bcolor.interaction.disabled.bg #0d07071.581pass

Keys

KeyAction
Tab / Shift+TabMoves focus in and out.
Space / Alt+DownOpens the themed popup without committing a choice.
Up / DownOpens the single list or moves its active option; Enter or Space commits. In the multiple list, moves the active option.
TypingMoves to an enabled option starting with the typed characters.
Space / click; Shift+Up / Shift+Down; Ctrl+Command+AToggles a multiple option; extends a range; selects or clears all enabled options.
Escape / TabCloses the single popup without committing the active option.

For agents

Component JSON ·Implementation brief ·Build a task kit ·

Related: combobox multiselect text-field field menu

Stress fixtures: FX-LONG FX-320 FX-ZOOM-200 FX-I18N FX-RTL FX-RM FX-HC FX-TOUCH FX-DENSITY FX-STATE-MATRIX