Skip to content

feat(design-library): add form input and navigation components#31087

Merged
ashleeradka merged 3 commits into
mainfrom
devin/1779156844-design-library-form-inputs
May 19, 2026
Merged

feat(design-library): add form input and navigation components#31087
ashleeradka merged 3 commits into
mainfrom
devin/1779156844-design-library-form-inputs

Conversation

@ashleeradka
Copy link
Copy Markdown
Contributor

@ashleeradka ashleeradka commented May 19, 2026

Prompt / plan

Port Tier 1 design library components from the platform repo to reduce diff noise in subsequent domain migration PRs. These 7 components cover 98 import sites across the platform codebase.

Components added:

  • Input + Textarea — single-line and multi-line text fields with labels, icons, error/helper text. Shared fieldVariants CVA.
  • Toggle — on/off switch with label and helper text. Exports handleToggleClick for testing.
  • Checkbox — tri-state Radix checkbox (boolean | "indeterminate") with label support.
  • Radio — generic RadioGroup<T> + Radio<T> with Radix primitives.
  • Tabs — compound Radix tabs (Root/List/Trigger/Panel) with themed styling.
  • SegmentControl — pill-shaped segmented control using Button. Exports resolveSegmentSelection for testing.
  • Slider — single-thumb and range mode with Radix primitives. Exports value conversion helpers.

Convention compliance applied during port:

  • Removed all "use client" directives (Vite SPA, no SSR)
  • Converted forwardRef → ref as regular prop (React 19)
  • Function declarations for all components (not arrow/const)
  • data-slot attributes on all root elements (shadcn/ui v4 convention)
  • Relative .js imports for NodeNext resolution
  • Named exports only (no default exports)
  • Exported variant functions and helper utilities alongside components
  • ComponentProps<"element"> instead of HTMLAttributes for element-specific props + ref

New Radix dependencies added (exact versions matching platform):

  • @radix-ui/react-tabs@1.1.13
  • @radix-ui/react-checkbox@1.3.3
  • @radix-ui/react-radio-group@1.3.8
  • @radix-ui/react-slider@1.3.6

Part of LUM-1543

Test plan

  • bunx tsc --noEmit passes in both packages/design-library/ and apps/web/
  • No existing imports are broken (all prior exports preserved)
  • CI lint + typecheck + build

Link to Devin session: https://app.devin.ai/sessions/536ceadb023a4059908b0609b9833bc1
Requested by: @ashleeradka


Open in Devin Review

Add 7 Tier 1 design library components ported from the platform repo:
- Input + Textarea (single-line and multi-line text fields with labels, icons, error/helper text)
- Toggle (on/off switch with label and helper text)
- Checkbox (tri-state Radix checkbox with label support)
- Radio (generic RadioGroup + Radio with Radix primitives)
- Tabs (compound Radix tabs with themed styling)
- SegmentControl (pill-shaped segmented control using Button)
- Slider (single-thumb and range mode with Radix primitives)

Convention compliance applied during port:
- Removed all 'use client' directives (Vite SPA)
- Converted forwardRef to ref-as-prop (React 19)
- Function declarations for all components
- data-slot attributes on all root elements
- Relative .js imports for NodeNext resolution
- Named exports only (no default exports)
- Exported variant functions and helper utilities for testing

Part of LUM-1543

Co-Authored-By: ashlee@vellum.ai <ashlee@vellum.ai>
@devin-ai-integration
Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@linear
Copy link
Copy Markdown

linear Bot commented May 19, 2026

LUM-1543

Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 potential issues.

View 3 additional findings in Devin Review.

Open in Devin Review

Comment thread packages/design-library/src/components/checkbox.tsx Outdated
Comment thread packages/design-library/src/components/toggle.tsx Outdated
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 910b266cd1

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/design-library/src/components/segment-control.tsx
- Toggle: add data-slot="toggle" to root <span> in no-label code path
- Checkbox: add data-slot="checkbox" to root <span> in no-label code path
- SegmentControl: implement roving tabindex + arrow/Home/End key handling
  for the radiogroup role (WAI-ARIA radiogroup pattern)

Co-Authored-By: ashlee@vellum.ai <ashlee@vellum.ai>
vex-assistant-bot[bot]
vex-assistant-bot Bot previously approved these changes May 19, 2026
Copy link
Copy Markdown
Contributor

@vex-assistant-bot vex-assistant-bot Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVE

Value: Eliminates ~98 platform import sites' worth of diff noise from upcoming domain migration PRs by landing the 7 most-used design-library components in one clean PR.

What this does: Ports Input, Textarea, Toggle, Checkbox, RadioGroup/Radio, Tabs, Slider, and SegmentControl from the platform repo into packages/design-library/. All components use Radix UI primitives, CSS variable tokens, and useId()-based a11y wiring.


Responding to bot findings:

Devin flagged data-slot missing from the no-label <span> wrapper in both Checkbox and Toggle. Partially valid:

  • Checkbox (line 96) — confirmed. The no-label path returns <span className={className}>{checkbox}</span> without data-slot="checkbox". The inner CheckboxPrimitive.Root still carries the slot, but the outer wrapper is inconsistent with the labeled path's <div data-slot="checkbox">. Worth a quick fix for selector consistency.
  • Toggle (line 86) — Devin's finding is incorrect here. The no-label span already reads <span data-slot="toggle" className={className}>. This one is fine as-is.

Codex P2 — SegmentControl keyboard navigation: Real gap. The component advertises role="radiogroup" + role="radio" but only handles onClick — AT users expect arrow keys to move between segments. Since this is a faithful port (not worse than the platform), acceptable to land now and file a follow-up ticket.


My observations:

--ghost-hover in tabs.tsx (non-blocking): TabsTrigger uses hover:bg-[var(--ghost-hover)]. Per the anti-patterns KB, --ghost-hover is exclusively for the ghost Button primitive — nav items, list rows, and tab triggers should use --surface-hover. This is a faithful port of whatever the platform uses, so not blocking this PR, but worth aligning in a follow-up cleanup pass.

Toggle Typography className redundancy (nit): toggle.tsx passes variant="body-medium-default" and then also adds "text-body-medium-default" to className. The other six components (checkbox, radio) pass the variant alone without repeating the class in className. Inconsistent but not broken.

Everything else is clean:

  • Radix primitives used correctly throughout — forceMount on Indicator for explicit icon control, roving tabindex inherited from RadioGroupPrimitive, aria-labelledby/aria-describedby wired up properly
  • FieldWrapper + fieldVariants (CVA) extracts the shared field chrome cleanly — both Input and Textarea share it without duplication
  • resolveSegmentSelection and handleToggleClick extracted as pure functions — testable without DOM
  • SliderValue = number | [number, number] union + isRangeValue / toValueArray / fromValueArray helpers are a nice touch for type-safe range mode
  • Token discipline consistent: no hex values, no ad-hoc Tailwind colors, all through CSS vars

Merge gate: Devin didn't APPROVE (found issues), Codex didn't 👍. Needs one more human or bot sign-off before merge. Suggest triggering a Devin re-review once the data-slot span is patched in Checkbox.

Reviewed at 910b266c

Vellum Constitution — Yours: design-library components that are token-consistent and Radix-backed let every future migration PR trust its building blocks without second-guessing the primitives.

…class in toggle

- TabsTrigger: replace --ghost-hover with --surface-hover (correct semantic
  token for nav-like elements; --ghost-hover is only defined in dark/velvet)
- Toggle: remove duplicate text-body-medium-default className since Typography
  variant='body-medium-default' already applies it

Co-Authored-By: ashlee@vellum.ai <ashlee@vellum.ai>
@devin-ai-integration
Copy link
Copy Markdown
Contributor

All findings from the bot review (at 910b266c) have been addressed in two follow-up commits:

06850de — data-slot + keyboard nav fixes:

  • Checkbox: added data-slot="checkbox" to no-label <span> root
  • Toggle: added data-slot="toggle" to no-label <span> root (bot was incorrect that it was already there — both paths had the same bug)
  • SegmentControl: implemented full WAI-ARIA radiogroup keyboard pattern — roving tabindex, Arrow Left/Right/Up/Down, Home/End, wraps around, skips disabled items

2738ff36 — token + redundancy fixes:

  • TabsTrigger: --ghost-hover--surface-hover (correct semantic token; --ghost-hover wasn't even defined in light theme)
  • Toggle: removed duplicate text-body-medium-default className (already applied by Typography variant="body-medium-default")

@ashleeradka ashleeradka merged commit 741b678 into main May 19, 2026
14 checks passed
@ashleeradka ashleeradka deleted the devin/1779156844-design-library-form-inputs branch May 19, 2026 02:36
devin-ai-integration Bot added a commit that referenced this pull request May 19, 2026
…ckfile

- Add .storybook/**/*.tsx to packages/design-library/tsconfig.json so the
  renamed preview.tsx is included in typechecking (was only .storybook/**/*.ts).

- Regenerate apps/web/bun.lock to include new Radix dependencies added by
  #31087 (react-checkbox, react-radio-group, react-slider, react-tabs).
  The previous lockfile had a stale snapshot of the design-library deps.

Co-Authored-By: ashlee@vellum.ai <ashlee@vellum.ai>
ashleeradka added a commit that referenced this pull request May 19, 2026
…to web app (#31089)

* fix(design-library): fix Storybook docs dark mode + add token import to web app

- Replace static preview.ts with preview.tsx that provides a custom
  ThemedDocsContainer. The container reads the current theme global via
  Storybook's DocsContextProps API and maps it to a matching Storybook
  theme (light/dark/velvet) created with create() from storybook/theming.
  This ensures all docs elements (wrapper, preview containers, headings,
  prop tables, code blocks) automatically pick up the correct theme
  colors through Storybook's ThemeProvider cascade.

- Add @import "@vellum/design-library/tokens.css" to apps/web/src/index.css
  so the web app gets the design system CSS variables that 12+ component
  files already reference (var(--surface-base), var(--content-default), etc.).
  This is the documented integration path from tokens.css and was tracked
  in LUM-1607.

Co-Authored-By: ashlee@vellum.ai <ashlee@vellum.ai>

* fix: add .storybook/*.tsx to tsconfig include + regenerate web app lockfile

- Add .storybook/**/*.tsx to packages/design-library/tsconfig.json so the
  renamed preview.tsx is included in typechecking (was only .storybook/**/*.ts).

- Regenerate apps/web/bun.lock to include new Radix dependencies added by
  #31087 (react-checkbox, react-radio-group, react-slider, react-tabs).
  The previous lockfile had a stale snapshot of the design-library deps.

Co-Authored-By: ashlee@vellum.ai <ashlee@vellum.ai>

---------

Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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