WebberUI

Spec Label Section

A product spec section styled like a nutrition label — rows stamp themselves in one by one as it scrolls into the window, and any row can expand to show notes and supporting links.

Loading preview…
npx shadcn@latest add https://webberui.com/r/spec-label-section.json

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

0.08
0.3
<SpecLabelSection />

Installation

npx shadcn@latest add https://webberui.com/r/spec-label-section.json

Or, once registries are configured in components.json, install it as @webberui/spec-label-section.

Usage

import {
  SpecLabelSection,
  type SpecItem,
} from "@/components/ui/spec-label-section";

const items: SpecItem[] = [
  {
    id: "battery",
    label: "Battery life",
    value: "38",
    unit: "hours",
    emphasis: true,
    detail: "Measured in continuous playback with active noise cancelling on at 50% volume.",
    links: [{ label: "Test method", href: "#" }],
  },
  { id: "weight", label: "Weight", value: "248", unit: "g" },
];

<SpecLabelSection
  title="Specs at a glance"
  subtitle="Model NC-900 · per pair"
  items={items}
/>;

Props

SpecLabelSection

PropTypeDefaultDescription
itemsSpecItem[]Spec item data
titleReact.ReactNodeSection title, also used as the aria label
subtitleReact.ReactNodeSubtitle below the title (model, serving size, and so on)
featureHeadingReact.ReactNode"Item"Column header: title of the feature column
valueHeadingReact.ReactNode"Spec"Column header: title of the value column
footnoteReact.ReactNodeSmall footnote at the bottom (separated by a thick rule)
openIdsstring[]Controlled mode: array of currently expanded row ids
defaultOpenIdsstring[][]Initial array of expanded ids in uncontrolled mode
onOpenChange(ids: string[]) => voidFires when the expanded state changes
staggernumber0.08Interval between each row's stamp-in (seconds)
delaynumber0Delay before the reveal starts (seconds)
durationnumber0.3Expand / collapse duration (seconds)
oncebooleantruePlay only the first time the element enters the viewport

SpecItem

FieldTypeDescription
idstringUnique key, used to match controlled expansion — keep it stable
labelReact.ReactNodeFeature / item name (left side of the row)
valueReact.ReactNodeMain value (format it yourself)
unitReact.ReactNodeUnit after the value (at a smaller size)
emphasisbooleanEmphasize this row with a thick rule and a larger number
detailReact.ReactNodeExplanatory note shown once expanded
linksSpecEvidenceLink[]Supporting links shown once expanded
FieldTypeDescription
labelReact.ReactNodeLink text
hrefstringLink URL (opens in a new tab)

How it works

  • Stamp-in: when the whole table scrolls into the window, each row settles down from a slightly larger scale, accompanied by a fade in and a touch of blur, stamping in row by row according to stagger. Set once={false} to replay it every time it enters the viewport.
  • Thick and thin rules: the outer frame, the signature thick black bar, and the bottom edge of the header are thick rules; ordinary rows are separated by thin gray lines, while emphasis rows switch to a thick black rule and enlarge the value, mimicking the hierarchy of a nutrition label.
  • Expandable rows: rows that carry detail or links show an indicator arrow and are clickable, expanding the note and supporting links below the row with a height transition; rows with neither render as static, non-interactive rows.
  • Controlled and uncontrolled: when openIds is not passed, the component manages the expanded state itself (use defaultOpenIds to set the initial one); passing openIds makes it fully controlled, synchronized through onOpenChange. Multiple rows may be expanded at once.

Accessibility

  • Expandable rows are native <button>s carrying aria-expanded and aria-controls; they are keyboard focusable and toggle with Enter / Space.
  • The expanded block is a role="region" that points back at its trigger row through aria-labelledby.
  • When title is provided, the section is associated with its heading through aria-labelledby.
  • Supporting links open with target="_blank" and carry rel="noopener noreferrer".
  • When the user has "reduce motion" enabled at the system level, the stamp-in and the expand transition are disabled and a static table is shown directly.

On this page