Skip to content

feat(tabs)!: rework component on a single items API - #399

Merged
YounixM merged 16 commits into
mainfrom
feat/rework-tabs-component
Sep 28, 2026
Merged

YounixM merged 16 commits into
mainfrom
feat/rework-tabs-component

Conversation

@H4ad

@H4ad H4ad commented Sep 17, 2026 •

Copy link
Copy Markdown
Contributor

What

This re-implements the tabs component on a single items API, following the spec defined at https://github.com/SigNoz/engineering-pod/issues/5991

On top of the API rework:

  • Items can render as links, with one router-owned panel instead of a panel per tab.
  • A vertical rail orientation, with the marks and bands laid out for it, and scroll buttons when the bar overflows.
  • The slider and axis maths moved to utils.ts, and the tabs are held to the React compiler strict check.
  • Trigger labels are capped at 120px through --tabs-trigger-label-max-width, and the primary trigger is centred and rounded.
  • Design-token fallbacks removed from tabs.module.scss, so every overridable value resolves to a token.
  • Storybook theme and motion moved onto toolbar globals with matching Chromatic modes, and both showcases document the state matrix.

Why

The tabs component predates the current guidelines: it exposed a compound API, left its layout values hardcoded, and had no vertical or overflow story.

How to verify

Storybook: Components/Tabs, plus the Tabs Root, Tabs List, Tabs Trigger and Tabs Content story files.

pnpm lint
pnpm run type-check
pnpm build
pnpm -F @signozhq/ui test:run

Component checklist

Philosophy (guidelines)

  • Variants represent meaningful roles (purpose), not one-off visual styling
  • All applicable states handled: default, hover, active, selected, focus, disabled, loading, invalid, read-only
  • Accessibility encoded in component: keyboard, focus, labels, ARIA (not left to consumer)
  • Complex behaviours split into composable patterns, not crammed into conflicting props
  • Escape hatches minimized; CSS overrides are last resort (if exception recurs, evolve the component)

Structure (guidelines)

  • Directory is kebab-case under packages/ui/src/, matches the export subpath
  • index.ts only re-exports (+ generated token region); export type * plus explicit named exports
  • Relative imports use the .js extension; types imported with import type
  • Subcomponents in subcomponents/, opinionated compositions in presets/
  • All four lists updated: src/index.ts, vite.config.ts, package.json exports, README.md + intro.mdx
  • New runtime deps added to externalPatterns

CSS (guidelines)

  • {name}.module.scss, no Tailwind, no CVA, no Sass variables
  • Every overridable value is var(--{component}-x, <design token>); no hardcoded values
  • No literal fallback on a design token (var(--spacing-4, 8px)); a bare literal only where no token matches
  • Colours use semantic tokens only, with no --bg-* / --text-* primitives referenced from a component
  • Values that must not be overridden use --{component}-internal-*
  • No --x: var(--x) and no duplicated variable definitions
  • Variants are data-* attributes; data-slot and data-testid on the root
  • color-mix() for derived shades, never rgba() over a token
  • :hover, :focus-visible, aria-invalid, disabled all styled
  • Transitions use the component's duration/easing tokens and are disabled under @media (prefers-reduced-motion: reduce)
  • pnpm run tokens run and the index.ts region committed

Visual QA (guidelines)

  • Compared against the Figma frame side by side: spacing, sizes, colours, every state
  • Figma frame linked from the story via parameters.design
  • Checked in light and dark
  • Sizing and density consistent with sibling components (sm matches Button / Input)
  • Typography via Typography or the type-scale tokens, not an ad-hoc font-size / font-weight
  • Icons from @signozhq/icons, sized with tokens, no inline SVG with hardcoded px
  • Every state built: default, hover, focus-visible, active, disabled, loading, invalid, selected, empty, long/truncated
  • Not a duplicate of an existing primitive or preset

Types (guidelines)

  • {Component}Props exported; only the props the component actually needs are exposed
  • Upstream-owned prop types borrowed by indexed access (OriginalProps['x']), never restated by hand
  • Every type named by a public prop is exported from index.ts
  • forwardRef with a named render function (or displayName); testId supported
  • Defaults in the destructuring; controlled/uncontrolled naming follows Radix

Docs (guidelines)

  • JSDoc on every public prop, with @default where applicable
  • Story file per root component and per preset, subcomponent stories in the parent's file (@access private ones exempt), correct title group
  • argTypes complete with category, type.summary, defaultValue.summary
  • Stories for every meaningful state, not just the happy path
  • {component}.mdx with a usage snippet and a <Controls> per exported piece

Tests (guidelines)

  • Behaviour test per interactive prop
  • forward-ref test
  • run-visual-testing label added if the change is visual

@H4ad
H4ad added this pull request to stack #386 September 17, 2026 21:18
@H4ad H4ad changed the title feat/rework tabs component feat(tabs): rework component on a single items API Sep 17, 2026
@H4ad
H4ad marked this pull request as ready for review September 17, 2026 21:19
@H4ad
H4ad requested a review from a team as a code owner September 17, 2026 21:19
@H4ad H4ad changed the title feat(tabs): rework component on a single items API feat(tabs)!: rework component on a single items API Sep 21, 2026
@H4ad
H4ad force-pushed the feat/rework-tabs-component branch 2 times, most recently from b268b31 to 488aeee Compare September 24, 2026 14:53
@H4ad
H4ad force-pushed the feat/rework-tabs-component branch from 488aeee to e43c3ea Compare September 24, 2026 19:44
@H4ad
H4ad force-pushed the feat/rework-tabs-component branch 2 times, most recently from 50648cf to d10c45a Compare September 25, 2026 17:45
@YounixM
YounixM force-pushed the feat/rework-tabs-component branch 11 times, most recently from 3a4af16 to d330faf Compare September 28, 2026 15:07
Base automatically changed from feat/rework-radio-group to main September 28, 2026 15:13
@YounixM
YounixM force-pushed the feat/rework-tabs-component branch from d330faf to d2ddd5f Compare September 28, 2026 15:13
@YounixM
YounixM merged commit 6e78128 into main Sep 28, 2026
5 checks passed
@YounixM
YounixM deleted the feat/rework-tabs-component branch September 28, 2026 15:20
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.

2 participants