VotingMedium

Add .switch toggle and .input-group (input with attached buttons/selects) form components

Proposed by Jonathan Miller 2 hours ago
Specification

Add .switch and .input-group form components

Motivation

.field covers labelled controls, but there is no toggle switch and no input with an attached button. In a benchmark, agents fell back to plain checkboxes and hand-wrote flex CSS for attached buttons, which violates AI Generation Rule 2 (no custom CSS). Both patterns should be first-class components.

Scope

.switch

Markup:

<label class="switch"><input type="checkbox" role="switch" checked> Require admin approval</label>
  • Styles the native input[type=checkbox] inside .switch with appearance: none, drawn as a track with a thumb (pseudo-element).
  • On state (:checked): the track uses --color-primary and the thumb moves to the end side.
  • :disabled gets reduced opacity and cursor: not-allowed. The label text is styled to match.
  • The thumb and track transition use --duration-fast and --ease-standard. Assumption: transitions are disabled under prefers-reduced-motion: reduce, if the framework already follows that pattern.
  • :focus-visible uses the existing --focus-* tokens.
  • Only existing tokens are used. Assumption: the switch dimensions are derived from existing size or spacing tokens, and new tokens are added only if they are documented in the token reference.

.input-group

Markup:

<div class="input-group"><input type="url" readonly value="…"><button type="button" class="button">Copy</button></div>
  • An inline flex row. Children can be input, select and .button.
  • Adjacent children share borders, with no doubled borders. Only the outer corners (first child's start and last child's end) are rounded. Inner corners are square.
  • Inputs grow (flex: 1 1 auto; min-width: 0). Buttons and selects keep their intrinsic size.
  • All children share a height that respects --input-height / --control-height.
  • A focused child's focus ring is not clipped by its neighbours (for example, by raising its z-index).
  • Assumption: non-button addons such as unit labels are out of scope unless the proposer confirms otherwise.

Contract and docs

  • Add both components to Component Vocabulary and Intent Mapping in synthcss.llm.md, with exactly one Valid Example each.
  • Mirror these additions in synthcss.ai.json so the existing sync verification passes.

Acceptance criteria

  • .switch is a native checkbox with role="switch". It toggles with Space, is reachable by Tab, and shows a visible focus ring.
  • .switch reflects checked and disabled with no extra classes.
  • .input-group joins an input with one or more .button and/or <select> children. The result has no doubled borders and rounded outer corners only, and needs no custom CSS.
  • Both components render correctly inside .field, alongside .field-label, .field-help and .field-error.
  • Both components use only existing design tokens (or newly documented ones). There are no hard-coded colours.
  • synthcss.llm.md and synthcss.ai.json are updated, and all existing tests, lint, build and sync-verification checks pass.
  • Tests are added or extended, following existing repo conventions (for example, CSS selector presence and contract sync), to cover the new classes.

Out of scope

  • JavaScript behaviour, such as copy-to-clipboard.
  • Size variants, vertical input groups, and addon text segments.
  • Showcase updates, unless the proposer confirms them.
Discussion · 0

No comments yet.