Section Label
A small editorial kicker for stand-alone sections — uppercase, mono-tracked, with an optional hairline rule that extends to the right edge of its row. Use it to label sections that sit outside any numbered figure system: a journey intro, a "what you built" recap, a single-step row.
The journey
Three ways to see it
Step 1
Step 2
Installation
npx shadcn@latest add https://craftbits.dev/r/section-label.jsonUsage
import { SectionLabel } from "@craft-bits/core";
<SectionLabel>The journey</SectionLabel>Swap the tone for an accent or status colour:
<SectionLabel tone="accent">Three ways to see it</SectionLabel>
<SectionLabel tone="success">Verified</SectionLabel>Drop the hairline for a tight inline render where two labels share a row:
<div className="flex items-center gap-6">
<SectionLabel decor="none">Step 1</SectionLabel>
<SectionLabel decor="none">Step 2</SectionLabel>
</div>Understanding the component
- Editorial kicker, not a heading. SectionLabel renders a small uppercase span, not a
<h2>/<h3>. Pair it with a heading underneath when you need an a11y landmark; keep it on its own when the section is purely visual. - Tone is semantic.
defaultis the muted kicker tone (--cb-fg-subtle);accent,success,warning,error,mutedthread the corresponding cb token colour through the label text. The hairline rule colour stays constant (--cb-border-muted) regardless of tone. - Decor controls the rule.
rule(default) draws anaria-hiddenhairline that fills the remaining row width;nonedrops the rule so the label collapses to its natural intrinsic width. - Children accept ReactNode. Compose icon + text, count badge + text, or any inline JSX — children are not forced to a string.
- Data hooks. The root carries
data-cb-section-label,data-tone, anddata-decorso consumers can target nested regions without re-deriving props.
Variants
Default kicker
<SectionLabel>The journey</SectionLabel>Accent tone
<SectionLabel tone="accent">Three ways to see it</SectionLabel>Inline pair, no rule
<div className="flex items-center gap-6">
<SectionLabel decor="none">Step 1</SectionLabel>
<SectionLabel decor="none">Step 2</SectionLabel>
</div>Props
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Label content. Rendered uppercase, mono-tracked. Accepts plain text or composed inline JSX. |
tone | 'default' | 'accent' | 'success' | 'warning' | 'error' | 'muted' | 'default' | Semantic colour of the label text. The hairline rule colour stays constant. |
decor | 'rule' | 'none' | 'rule' | Decorative element rendered after the label. rule draws an aria-hidden hairline; none drops it. |
className | string | — | Merged onto the rendered <div> via cn(). |
...rest | HTMLAttributes<HTMLDivElement> | — | Any other <div> attribute. |
Accessibility
- The decorative hairline is
aria-hidden— never announced to assistive tech. - The label itself is a plain
<span>inside the row. It is not a heading or landmark; pair it with a heading element when the section needs an a11y title. - Colour contrast: every tone reads from the cb token system, where each colour clears WCAG AA on the default
--cb-bgand--cb-bg-elevatedsurfaces. - No motion. Reduced-motion respect is the responsibility of the surrounding content.
Credits
- Extracted from:
algoflashcards(src/lessons/primitives/chrome/SectionLabel.tsx). The original threaded a hexaccentHexprop directly onto an inlinestyleattribute and accepted a binaryhairlineprop. craft-bits replaces the hex prop with a semantictonetoken and renameshairlinetodecorto leave room for future decorative variants.