Skip to content

feat(core): Tabs component for json-render, with real per-component prop types - #492

Open
dvcolomban wants to merge 2 commits into
vitejs:mainfrom
dvcolomban:feat/json-render-tabs-typed-elements
Open

feat(core): Tabs component for json-render, with real per-component prop types#492
dvcolomban wants to merge 2 commits into
vitejs:mainfrom
dvcolomban:feat/json-render-tabs-typed-elements

Conversation

@dvcolomban

@dvcolomban dvcolomban commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a Tabs primitive to the json-render base catalog — previously there was no way to group content into tabs, and devtoolsRegistry had no plugin-side registration hook, so this had to land as a first-class catalog component.

  • New components/Tabs.ts: tabs[] descriptors (value, label, optional icon/badge/badgeVariant), children[i] ↔ tabs[i] so panels can't desync from their tab, and only the active child renders.
  • Controlled via value/$bindState, or uncontrolled via defaultValue (falls back to tabs[0]) — same useBoundProp + ctx.on('change') pattern as Switch.
  • orientation: 'horizontal' | 'vertical' (default horizontal), with matching a11y: role="tablist"/"tab", aria-selected, aria-orientation, roving tabindex, and arrow-key navigation.
  • Fixed border-radius to be orientation-aware (folder-tab rounding only makes sense horizontally — it looked odd applied to a vertical rail).
  • This is also the first catalog component whose props were complex enough to warrant real typing, so it's paired with co-located Props interfaces exported from the existing public webcomponents/index.ts barrel (JsonRenderElement, TabDescriptor, TabsProps) — opt-in, the untyped JsonRenderElement from @vitejs/devtools-kit is untouched.

Screenshots

01-horizontal-default 02-horizontal-gateway-active 03-vertical 04-vertical-arrowdown-nav 06-vertical-hover-corner-check 09-card-stack-composition 10-gateway-card-composition

Test plan

  • pnpm run lint
  • pnpm run typecheck
  • Storybook Tabs story: exercised both orientations, arrow-key navigation, and a composed Stack+Card tab panel

@pkg-pr-new

pkg-pr-new Bot commented Jul 28, 2026

Copy link
Copy Markdown

Open in StackBlitz

@vitejs/devtools

npm i https://pkg.pr.new/@vitejs/devtools@492

@vitejs/devtools-kit

npm i https://pkg.pr.new/@vitejs/devtools-kit@492

@vitejs/devtools-oxc

npm i https://pkg.pr.new/@vitejs/devtools-oxc@492

@vitejs/devtools-rolldown

npm i https://pkg.pr.new/@vitejs/devtools-rolldown@492

@vitejs/devtools-vite

npm i https://pkg.pr.new/@vitejs/devtools-vite@492

@vitejs/devtools-vitest

npm i https://pkg.pr.new/@vitejs/devtools-vitest@492

commit: 8d2395c

@dvcolomban
dvcolomban force-pushed the feat/json-render-tabs-typed-elements branch from a0c6a77 to 9e07035 Compare July 28, 2026 17:02
…rop types

Adds `Tabs` to the json-render base catalog — horizontal (underlined bar) or
vertical (left rail) — since building a tabbed panel today means either a
Card per section or client-side `visible` wiring the spec author has to
build themselves. `children[i]` renders when `tabs[i]` is active, so there's
no `visible` plumbing needed in the spec; two-way bindable via `$bindState`
on `value`, otherwise switches local uncontrolled state. Includes roving
-tabindex keyboard navigation (arrow keys, Home/End) per the WAI-ARIA tabs
pattern.

Also types `Tabs`' own props (`TabsProps`, `TabDescriptor`) co-located in
`Tabs.ts` itself, and adds `registryProps<Type, Props>()` — a typed
alternative to the untyped `props: ['element', 'emit', ...]` array form
every registry component currently uses, so `defineComponent` infers
`setup`'s `ctx.element.props` as the component's own type instead of
`Record<string, any>`. `RegistryComponentProps` stays generic with the same
permissive default, so every other untouched component is unaffected.

`TabsProps`/`TabDescriptor` are re-exported from the client webcomponents
entry (`@vitejs/devtools/client/webcomponents`, already public) as opt-in
strict types — most spec authors keep using kit's fully open
`JsonRenderElement`. Deliberately not added to `@vitejs/devtools-kit`:
kit depends on nothing in core (core depends on kit, so the reverse would
cycle), and duplicating each component's props into a second, separately
-maintained types package is exactly the drift risk co-location avoids.
@dvcolomban
dvcolomban force-pushed the feat/json-render-tabs-typed-elements branch from 9e07035 to 661169d Compare July 28, 2026 17:14
@dvcolomban
dvcolomban marked this pull request as ready for review July 28, 2026 17:21
…bs-typed-elements

# Conflicts:
#	packages/core/src/client/webcomponents/index.ts
#	test/__snapshots__/tsnapi/@vitejs/devtools/client/webcomponents.snapshot.d.ts
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