Skip to content

UN-4300 [FEAT] Add the v1 toggles: Checkbox, Radio and RadioGroup, Switch and Slider (P1-T05) - #2462

Open
praveen-formido wants to merge 12 commits into
mainfrom
UN-4300-toggles
Open

praveen-formido wants to merge 12 commits into
mainfrom
UN-4300-toggles

Conversation

@praveen-formido

@praveen-formido praveen-formido commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

What

  • Frontend v1 toggles (P1-T05), in frontend/src/v1/components/ui/toggles/, on Radix (radix-ui named imports) and the P0-T04 tokens:
    • Checkbox (16): checked, unchecked and mixed (checked="indeterminate", controlled only; defaultChecked is narrowed to boolean on purpose), Space toggles.
    • Switch (20 × 36): role="switch" exposing on and off, Space toggles.
    • Radio (14) and RadioGroup: arrows move selection and focus together and skip a disabled item; the group is named by its label (rendered heading, aria-labelledby) or the caller's aria-label; a disabled group dims its heading and item labels.
    • Slider: label line with an optional shown value, description, one or more thumbs; arrows, PageUp/PageDown, Home and End; every thumb has an accessible name (thumbLabels[i], then a string label, then the root's aria-label; a range without thumbLabels keeps Radix's "Minimum"/"Maximum") and aria-valuetext from formatValue; the root is a named role="group" and each thumb carries the description and aria-disabled.
    • Every control has a label slot and an optional description, drawn by one private ControlRow (control centred on a 20px label line, description below), which wires htmlFor and aria-describedby and dims the label when disabled.
  • toggles.gallery.tsx lists every variant and state (21 entries); markup.test.tsx snapshots each one to __snapshots__/markup.md and runs axe on each, the same way ui/code does. A README in the folder and a Toggles section in src/v1/README.md.

Why

  • P1-T05 (UN-4300, spec): the small controls every v1 form uses. It unblocks P1-T06 (form system, lane B) and P1-T11 (data table, lane F).

How

Decision Why
Sizes from dev-spec board § 5: checkbox ui:size-4, radio ui:size-3.5, switch ui:h-5 ui:w-9 with a ui:size-4 thumb, slider track ui:h-1.5 Spacing steps are 4px, so 16, 14, 20 × 36 and 6 are exact. No kit component exists for any of the four; the board is the contract.
Focus, disabled and selection from board § 6: ui:focus-visible:focus-ring; disabled is opacity-50 + pointer-events-none; selected fill primary, rest border input; no hover fill § 6 lists hover for rail, menu, icon buttons and rows only.
Checkbox radius is ui:rounded-sm (6px) The kit draws 4px, but no 4px radius token exists and v1 forbids raw lengths. Open design question since P1-T03.
The checkbox icon is the Radix Indicator rendered asChild onto the lucide svg, and the icon (Check or Minus) is chosen in JS v0's global svg.lucide rule forces any lucide icon under a span/p/label/li/a/td/th to 1em inline-block and is unlayered, so a ui:size-* on the svg loses and a CSS hidden cannot hide the wrong icon. With the svg's parent being the button the rule never matches.
Labels and descriptions are drawn by ControlRow, with the same classes as Label/HelperText in #2416 (P1-T03), not imported from it #2416 is unmerged. The hand-off to Field is documented in the README: toggles read useFieldControl in P1-T06; RadioGroup never goes inside Field (a <label for> cannot name a radiogroup); until then, do not put a toggle inside Field.
Mixed is controlled only The icon comes from checked; defaultChecked="indeterminate" would announce "mixed" while drawing a tick, so the type rejects it.
className lands on the outermost element of every component So <Slider className="ui:max-w-xs"> narrows the label line and the track together. Only horizontal sliders are supported (orientation is omitted from the props).
Gallery exports stay out of index.ts ui/code does the same; the P1-T01 gallery imports ./toggles.gallery directly.

Can this PR break any existing features. If yes, please list possible items. If no, please explain why. (PS: Admins do not merge the PR without this section filled)

  • No. Everything is new under frontend/src/v1/components/ui/toggles/ plus a section in src/v1/README.md. No v0 file, dependency or build file changes, and no v0 route renders v1.

Database Migrations

  • None.

Env Config

  • None.

Relevant Docs

Related Issues or PRs

Dependencies Versions

  • None.

Notes on Testing

  • 48 vitest tests in the folder (behaviour and keyboard: Space, arrows with a disabled item skipped, Home/End, mixed → checked on Space, controlled and uncontrolled values, descriptions on the focusable element, click on control and label, disabled) plus the markup snapshot and an axe scan per gallery entry. Every behavioural guard was mutation-checked: removing it fails a test.
  • bun run test:v1: 429 tests across 48 files, coverage 97.6% lines / 94.8% branches / 93.9% functions; lint:v1, typecheck:v1 and biome ci src/v1 clean.
  • Sizes are pinned by class in tests (happy-dom has no layout); the real geometry is for the P1-T01 gallery visual check.
  • Reviewed with a per-task review and a whole-branch review; the branch's rulings are in claudedocs/frontend-v1-lane-c/plans/2026-11-09-P1-T05-sdd-ledger.md (not committed).

🤖 Generated with Claude Code

@greptile-apps

greptile-apps Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

via Greptile

RetriggerView in GreptileConfidence Score: 5/5

[Low impact] The PR appears safe to merge; no new actionable issue was established.

Summary

Adds reusable v1 checkboxes, switches, radio groups, and sliders built on Radix.

  • Checkboxes show unchecked, checked, and mixed choices.
  • Switches show on and off settings.
  • Radio groups let people choose one option from a set.
  • Sliders adjust one value or a range of values.
  • Toggle labels sit beside their controls, with help text below.
  • V1 forms can import the toggle set and find its examples.

The earlier single-thumb naming issue is fixed. Its thread is unnumbered, so it has no numbered finding entry.

The previous-review merge bases differ, so this review used the full PR changes. Tests and browser checks were not run; dependencies are not installed, and no page currently renders the gallery.

Reviews (3) · Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." · Reviewed by Greptile

@praveen-formido praveen-formido added the main-only Stays on main: not backported to a release line label Nov 9, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Frontend Lint Report (Biome)

✅ All checks passed! No linting or formatting issues found.

@sonarqubecloud

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown
Contributor

Unstract test results

Per-group results

Status Group Tier Passed Failed Errors Skipped Duration (s)
⚪ e2e-agent-kv e2e 0 0 0 1 0.0
✅ e2e-api-deployment e2e 3 0 0 0 11.6
✅ e2e-coowners e2e 1 0 0 0 0.8
✅ e2e-etl e2e 1 0 0 0 15.7
✅ e2e-login e2e 2 0 0 0 0.9
✅ e2e-prompt-studio e2e 1 0 0 0 10.2
✅ e2e-smoke e2e 2 0 0 0 0.7
✅ e2e-workflow e2e 1 0 0 0 13.7
❌ ui e2e 0 1 0 0 0.0
TOTAL 11 1 0 1 53.6

Critical paths

⚠️ Critical paths not yet covered

  • workflow-execution-fan-out — Multi-file workflow execution fans out to file-processing workers and rejoins. (declared coverage: no groups declared)
💤 Covered, but not exercised in this build
  • adapter-register-llm — Register and validate an LLM adapter. (covered by integration-backend; no result reported in this build)
  • workflow-author — Create a workflow; its source+destination endpoints materialise and are configurable. (covered by integration-backend; no result reported in this build)
  • api-deployment-provision — Deploying a workflow as an API mints a usable key and a resolvable endpoint. (covered by integration-backend; no result reported in this build)
  • api-deployment-auth — Unauthenticated or mis-scoped API-deployment calls are rejected before dispatch. (covered by integration-backend; no result reported in this build)
  • mcp-server-auth — Unauthenticated or mis-scoped hosted-MCP calls are rejected before any tool runs. (covered by integration-backend; no result reported in this build)
  • mcp-platform-auth — The org-scoped MCP endpoint stays behind the platform-API-key middleware; unauthenticated or mis-scoped calls reach no tool. (covered by integration-backend; no result reported in this build)
  • platform-key-whoami — A platform API key resolves its own organisation over the org-less whoami endpoint; the org comes from the key row, not the URL. (covered by integration-backend; no result reported in this build)
  • prompt-studio-author — Create a Prompt Studio project and add a prompt to it. (covered by integration-backend; no result reported in this build)
  • connector-register-test — Connector credentials are validated against the live system and stored encrypted. (covered by integration-backend; no result reported in this build)
  • usage-aggregate-read — Per-run token usage aggregates correctly and stays scoped to its organization. (covered by integration-backend; no result reported in this build)
✅ Covered critical paths
  • auth-login — covered by e2e-login
  • co-owner-manage — covered by e2e-coowners
  • workflow-create-execute — covered by e2e-workflow
  • api-deployment-run — covered by e2e-api-deployment
  • prompt-studio-fetch-response — covered by e2e-prompt-studio
  • pipeline-etl-execute — covered by e2e-etl
  • usage-token-tracking — covered by e2e-api-deployment
  • callback-result-delivery — covered by e2e-api-deployment

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

main-only Stays on main: not backported to a release line

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant