Skip to content

feat(RadioGroup): add single-choice control (17th atom, D22)#155

Merged
dgraciac merged 1 commit into
mainfrom
feat/radio
Jul 15, 2026
Merged

feat(RadioGroup): add single-choice control (17th atom, D22)#155
dgraciac merged 1 commit into
mainfrom
feat/radio

Conversation

@dgraciac

Copy link
Copy Markdown
Member

What

Adds RadioGroup + RadioGroupItem, the 17th Pharos atom — a set of mutually exclusive options (the shadcn RadioGroup contract) over Base UI's RadioGroup + Radio. It completes the boolean/choice form-control family: Checkbox (D20) → Switch (D21) → Radio.

Design (D22)

  • Compound (RadioGroup + RadioGroupItem), unlike the self-contained Checkbox/Switch: the selection semantics (single choice, arrow-key navigation, submitted value, name) live on the group, matching shadcn and the ARIA APG radiogroup pattern.
  • Canonical shadcn naming: the item is RadioGroupItem (not Base UI's Radio). data-pharos-slot = radio-group / radio-group-item.
  • Shared form-control conventions: label-less (Escuela 1, D11) — pair the group with <label>/aria-labelledby and each item with <label htmlFor>; no size axis in v1.
  • Error is a group concern: aria-invalid goes on the RadioGroup and every item shows the error ring (.group[aria-invalid] .item), not per-control.
  • Ring-with-dot, token-derived: circular 20px (spacing-5) control; the ring darkens to neutral-900 on selection (the family "active" color) and an inner dot (spacing-2) appears — deliberately distinct from Checkbox's filled square. The dot is a <span> (Base UI mounts the Indicator only while selected) — no icon dependency.

Changes

  • src/components/RadioGroup.{tsx,module.css,stories.tsx} + tests/RadioGroup.test.tsx (9 unit tests).
  • Exports in src/index.ts; D22 entry in NAMING-decisions.md; minor changeset.
  • Rule chore(deps): batch apply open dependabot bumps #8 (harness): Settings form gains a "Theme" radio group (light/dark/system); settings.spec.ts picks a value, asserts single-selection, and exercises arrow-key navigation.

Verification (all local, green)

  • pnpm build (+ verify:dist-types), pnpm typecheck, pnpm lint
  • pnpm test214/214 (RadioGroup 9/9)
  • pnpm test:storybook (axe a11y) — 106/106 (+4 RadioGroup stories)
  • pnpm build-storybook
  • pnpm --filter @examples/saas-demo test:e2e26/26 (incl. picks a single theme in the radio group)

Notes

  • New atom → Chromatic will request approval of the new RadioGroup snapshots (normal, reviewer action).
  • The unit Select 'closes on Escape…' flake is pre-existing (green in CI) — unrelated.

🤖 Generated with Claude Code

https://claude.ai/code/session_01AgnovjGivnndpV7Yzt6AmY

RadioGroup + RadioGroupItem is the shadcn "RadioGroup" contract over Base UI's
RadioGroup + Radio — role="radiogroup"/role="radio", arrow-key navigation,
single selection, hidden form input, shared Button/Input/Checkbox/Switch focus
ring. Completes the boolean/choice form-control family: Checkbox -> Switch ->
Radio.

- Compound (group + item), unlike the self-contained Checkbox/Switch: the
  selection semantics (single choice, arrow nav, submitted value, name) live on
  the group, matching shadcn + ARIA APG. shadcn naming (RadioGroupItem, not
  Radio); data-pharos-slot radio-group / radio-group-item.
- Shared form-control conventions: label-less (Escuela 1, D11), no size axis.
  Error is a group concern -> aria-invalid on the group, every item shows the
  ring (.group[aria-invalid] .item), not per-control.
- Ring-with-dot look, token-derived: circular 20px (spacing-5) control, ring
  darkens to neutral-900 on select (family "active" color) + inner dot
  (spacing-2). Dot is a span (Base UI mounts Indicator only when checked),
  no icon dep.
- Stories (Default + WithDisabledItem + Disabled + Invalid), unit tests (9),
  NAMING-decisions D22, changeset minor.
- Harness (rule #8): Settings form gains a "Theme" radio group
  (light/dark/system); settings.spec picks + enforces single selection + arrow
  nav -- 26 e2e specs.

Verified: build + dist-types, typecheck, lint, unit (RadioGroup 9/9, 214
total), test:storybook a11y (106 stories, +4), build-storybook, e2e 26/26.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AgnovjGivnndpV7Yzt6AmY
@chromatic-com

chromatic-com Bot commented Jul 15, 2026

Copy link
Copy Markdown

Tip

All tests passed and all changes approved!

🟢 UI Tests: 4 visual and accessibility changes accepted as baselines
🟢 UI Review: Approved by David Gracia
Storybook icon Storybook Publish: 106 stories published

@dgraciac
dgraciac merged commit 9781926 into main Jul 15, 2026
12 checks passed
@dgraciac
dgraciac deleted the feat/radio branch July 15, 2026 21:15
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