Wordmark

A typographic brand mark — a two-part word (serif italic + upright sans) followed by a small accent symbol. Useful as a header logo without packaging a separate SVG. The root element is polymorphic — render as a span, an h1/h2 heading landmark, or an a link.

craftbits
Customize
Scale
md
Tone
accent
Element
span

Installation

npx shadcn@latest add https://craftbits.dev/r/wordmark.json

Usage

Drop a Wordmark anywhere you'd otherwise drop a logo. The default text is the two-part "craft" + "bits" split with a single asterisk accent.

import { Wordmark } from "@craft-bits/core";
 
<Wordmark />

Override the text — accepts either a single string (no split) or a [serif, sans] tuple:

<Wordmark text={["after", "noon"]} />
 
<Wordmark text="Acme" />

Swap the accent symbol — strings, SVGs, or null to omit:

<Wordmark accent="·" />
<Wordmark accent={<StarIcon />} accentColor="warning" />
<Wordmark accent={null} />

Render as a heading landmark or a link:

<Wordmark as="h1" size="xl" />
 
<Wordmark as="a" href="/" />

Understanding the component

  1. Polymorphic root. The as prop picks the rendered tag — span keeps the mark inline, h1 and h2 give it heading semantics, and a turns it into a link that accepts href. The accent glyph nudges with a subtle hover transition only when the root is an anchor.
  2. Split text by default. text defaults to ["craft", "bits"]. Passing a tuple styles the first half serif italic and the second half upright sans. Passing a single string skips the split — the whole word renders upright. Either form keeps the same family/size pairing so consumers can swap word without re-tuning typography.
  3. Accent as a slot. accent accepts any ReactNode. A plain asterisk (default) renders inline with the serif family — the same font as the rest of the wordmark, so it sits on the baseline. Pass a custom SVG for a star, sparkle, or icon glyph. Pass null for a clean text-only wordmark.
  4. Size scales as one unit. The size prop sets the root font-size; everything inside inherits 1em so the accent glyph stays optically proportional. Four steps — sm (0.875rem), md (1.375rem, default), lg (1.875rem), xl (2.5rem) — cover sidebar labels through hero-page splashes.
  5. Tone-coded accent. accentColor picks a semantic tone (accent / success / warning / error) keyed to the cb-* tokens. The default matches the library accent; the semantic tones let the mark double as a status badge in error / empty states.
  6. Font fallback safe. The serif half resolves to var(--cb-font-serif, ui-serif, Georgia, serif) — if a consumer hasn't defined a serif token, the system serif keeps the visual contrast.
  7. Data-attributes for nested styling. The root carries data-cb-wordmark, data-size, and data-accent-color, and each child renders data-cb-wordmark-part="serif|sans|accent" — so consumers can target the accent glyph (e.g. animate it externally) without re-deriving props.

Props

Wordmark

PropTypeDefaultDescription
textstring | [string, string]["craft", "bits"]Either a single string (no split) or a [serif, sans] tuple.
accentReactNode"*"Small accent symbol rendered after the text. Pass null to omit.
accentColor'accent' | 'success' | 'warning' | 'error''accent'Tone of the accent glyph.
size'sm' | 'md' | 'lg' | 'xl''md'Root font-size — the accent glyph inherits at 1em.
as'span' | 'h1' | 'h2' | 'a''span'Root element. a accepts href and gets a hover nudge on the accent.
hrefstringLink target. Only used when as="a".
classNamestringMerged onto the rendered root via cn().
...restOmit<HTMLAttributes<HTMLElement>, 'title'>Any other root attribute.

Accessibility

  • The accent glyph is decorative — it renders with aria-hidden="true" so screen readers announce only the wordmark text, not the asterisk / star / sparkle.
  • When as="a", the link gets a visible :focus-visible outline keyed to --cb-accent and meets the 3:1 contrast bar against every default surface.
  • When as="h1" or as="h2", the mark is a landmark heading — keep at most one h1 per page.
  • Color contrast: the text uses --cb-fg; every accent tone passes WCAG AA against the default surfaces.
  • Motion: the only animation is a 300ms rotation on the accent glyph when the link is hovered. It uses transition-transform (no transition-all) and is below the library's 300ms motion cap. The base span / heading variants ship zero motion.

Credits

  • Extracted from: craftingattention (app/src/components/ui/Wordmark.tsx). The original was a fixed two-mode (full / compact) sparkle SVG + sans-serif text pair with hardcoded --color-accent-500 / --color-ink-50 tokens. craft-bits drops the inline SVG, generalises the surface into a polymorphic, scalable, theme-aware primitive — text becomes a tuple slot, the accent becomes a ReactNode slot, color and size become tokens, and the root tag becomes polymorphic so the same primitive serves headers, headings, and links.