Status Glyph
Five glyphs share one chassis so "succeeded", "failed", "loading", "neutral", and "warned" read with identical weight and alignment wherever they appear (list rows, toasts, build logs, request panels). The icon is purely a glyph — the parent decides whether to wrap it in a tooltip, button, or label. Tint flows through currentColor.
Customize
Glyph
check
md
currentColor
Installation
npx shadcn@latest add https://craftbits.dev/r/status-glyph.jsonUsage
import { StatusGlyph } from "@craft-bits/core/svg/status-glyph";
<span className="text-cb-success">
<StatusGlyph status="check" />
</span>Understanding the component
- One chassis, five glyphs. All five share a
0 0 16 16viewBox, the samecurrentColorfill/stroke discipline, and the same baseline alignment. Swappingstatusnever shifts row layout. - Tint inheritance, not a colour prop.
currentColorcascades from the wrapping element, so the same icon reads as success-green inside atext-cb-successrow and error-red inside atext-cb-errortoast.accentColoris the per-render override when inheritance isn't enough. - Spinner uses injected CSS, not a JS loop. The rotation lives in a single
@keyframesrule wrapped in@media (prefers-reduced-motion: no-preference)— the rule is appended to<head>the first time a spinner mounts. Reduced-motion users see a static three-quarter ring with no JS branch. - Generalised from the source. AlgoFlashcards'
StatusGlyphmixed authoring metadata (draft / in-design / ready / shipped) with per-user completion and wrapped itself in a tooltip. The library variant keeps only the universally meaningful icons, drops the tooltip wrapping, and forwards the ref to the underlying<svg>— matching every other@craft-bits/core/svg/*primitive.
Variants / Examples
// All five glyphs at the default 16px size.
<StatusGlyph status="check" />
<StatusGlyph status="cross" />
<StatusGlyph status="spinner" />
<StatusGlyph status="dot" />
<StatusGlyph status="warning" />
// Size tokens (sm = 12px, md = 16px, lg = 20px).
<StatusGlyph status="check" size="sm" />
<StatusGlyph status="check" size="lg" />
// Per-render colour override (wins over currentColor).
<StatusGlyph status="warning" accentColor="#f59e0b" />
// Mark decorative — the parent owns the accessible label.
<button aria-label="Retry">
<StatusGlyph status="spinner" ariaLabel={null} />
</button>Props
| Prop | Type | Default | Description |
|---|---|---|---|
status | "check" | "cross" | "spinner" | "dot" | "warning" | — | Which glyph to render. |
size | "sm" | "md" | "lg" | "md" | Pixel diameter (12 / 16 / 20). The viewBox stays 0 0 16 16. |
accentColor | string | — | CSS colour applied as inline color. Wins over currentColor inheritance. |
ariaLabel | string | null | per-status default | Accessible label. Pass null to mark the glyph decorative (aria-hidden). |
className | string | — | Extra classes merged onto the root <svg>. |
...rest | SVGAttributes<SVGSVGElement> | — | Forwarded to the root <svg> (except viewBox and fill, which the component owns). |
Accessibility
- Each
statusships a sensible defaultaria-label("Success","Error","Loading","Status","Warning") and renders withrole="img". Override viaariaLabel. - Pass
ariaLabel={null}to mark the glyph decorative — the component setsaria-hidden="true"and drops the role, so the parent owns the announcement. - The spinner rotation is gated by
@media (prefers-reduced-motion: no-preference). Users with reduced motion enabled see a static three-quarter ring, no JS branch needed. - Colour tinting flows through
currentColor, so the icon inherits whatever contrast the wrapping surface already meets.
Credits
- Extracted from:
AlgoFlashcards(src/platform/ui/StatusGlyph.tsx).