apx-dsv0.1Local renderer · live
K
Foundations4
  • Getting started
  • Theming
  • Templates
  • Icons
  • Avatar
  • Badge
  • DataGrid
  • Scheduler
  • Stat
  • Table
  • Timeline
  • TreeView
  • Accordion
  • Alert
  • EmptyState
  • Progress
  • Skeleton
  • Spinner
  • SplashScreen
  • Toast
  • ColorPicker
  • FileUpload
  • Form
  • Rating
  • TagsInput
  • Combobox
  • Field
  • Select
  • Toggle
  • Button
  • Calendar
  • Checkbox
  • DatePicker
  • Input
  • NumberInput
  • Radio
  • Slider
  • Switch
  • Textarea
  • AppShell
  • Div
  • Divider
  • Marquee
  • Parallax
  • Reveal
  • Section
  • SectionHeading
  • Sidebar
  • Stack
  • Surface
  • Typography
  • Image
  • Breadcrumbs
  • Carousel
  • NavigationMenu
  • Pagination
  • Stepper
  • Tabs
  • Toolbar
  • CommandPalette
  • Confirm
  • Drawer
  • HoverCard
  • Menu
  • Modal
  • Popover
  • Tooltip
  • Icon
  • Card
  • PricingCard
66 componentsapx-ds/renderer
Typography
Variant↳ other

Layout

Typography

Text primitive. A variant-driven

Typography

<Typography /> (also exported as <Text />) is the DS's canonical text primitive — a variant-driven sibling of <Div />. Pick a variant and you get the right semantic element (<h1> / <p> / <span> / <code>), a curated visual treatment from the DS typography scale, and the entire <Div /> styling surface (CSS shorthand, pseudo-state hooks, polymorphism, animation, responsive show / hide) inherited verbatim.

Reach for <Typography /> whenever you'd otherwise hand-roll <h1 className="text-4xl font-semibold tracking-tight">…</h1> or <p className="text-sm text-fg-muted">…</p>. The variant carries the styling intent, the shorthand props let you nudge any axis without dropping into sx, and the token-aware resolver maps fontSize="lg" → var(--sds-font-size-lg) so mode / variant switching is a no-op for the type system.

Anatomy

tsx
import { Typography, Text } from 'apx-ds';

<Typography variant="h1">Page title</Typography>             {/* renders <h1> */}
<Typography variant="body">Paragraph body</Typography>        {/* renders <p>  */}
<Typography variant="caption">Caption</Typography>             {/* renders <span> */}
<Typography variant="code">const x = 42;</Typography>          {/* renders <code> */}

<Typography fontSize="2xl" weight="semibold" lineHeight="tight" letterSpacing="tight">
  Custom-sized header without a variant.
</Typography>

<Typography truncate>Single-line ellipsis…</Typography>
<Typography lineClamp={3}>Up to three lines, then ellipsis…</Typography>

<Typography align="center" italic decoration="underline">
  Centered italic underlined
</Typography>

<Typography variant="body" actLike="a" href="/docs">
  Body-styled paragraph rendered as an anchor.
</Typography>

<Text variant="caption" color="fg.muted">Updated 3 minutes ago</Text>
import { Typography, Text } from 'apx-ds';

<Typography variant="h1">Page title</Typography>             {/* renders <h1> */}
<Typography variant="body">Paragraph body</Typography>        {/* renders <p>  */}
<Typography variant="caption">Caption</Typography>             {/* renders <span> */}
<Typography variant="code">const x = 42;</Typography>          {/* renders <code> */}

<Typography fontSize="2xl" weight="semibold" lineHeight="tight" letterSpacing="tight">
  Custom-sized header without a variant.
</Typography>

<Typography truncate>Single-line ellipsis…</Typography>
<Typography lineClamp={3}>Up to three lines, then ellipsis…</Typography>

<Typography align="center" italic decoration="underline">
  Centered italic underlined
</Typography>

<Typography variant="body" actLike="a" href="/docs">
  Body-styled paragraph rendered as an anchor.
</Typography>

<Text variant="caption" color="fg.muted">Updated 3 minutes ago</Text>

Prop surface

Variants (13)

GroupVariantDefault elementNotes
Displaydisplay<h1>Oversize hero. Still semantically a top-level heading.
Headingsh1–h6<h1>–<h6>One-to-one semantic mapping.
BodybodyLarge<p>Lead paragraph density.
body<p>Default. The page baseline.
bodySmall<p>Helper / footnote density.
Supportingcaption<span>Muted by default. Inline metadata.
overline<span>Uppercase + wider tracking. Section eyebrows.
code<code>Mono font, subtle background, inline code spans.

as / actLike always override the default element (matches <Div />'s rules — actLike wins over as and emits the same dev warning when both are provided).

Token-aware shorthand (5)

Each prop accepts either a documented token key (resolved to var(--sds-font-...)) or any raw CSS value (number / px string / inherit / 'Helvetica Neue', sans-serif / …) — unknown strings pass through untouched, so consumers always retain a per-prop CSS escape hatch.

PropToken keysCSS var
fontSizexs sm base lg xl 2xl 3xl 4xl 5xl--sds-font-size-{key}
weight / fontWeightnormal medium semibold bold--sds-font-weight-{key}
lineHeightnone tight snug normal relaxed--sds-line-height-{key}
letterSpacingtight normal wide wider--sds-letter-spacing-{key}
fontFamilysans mono display--sds-font-sans / --sds-font-mono / --sds-font-display

weight and fontWeight are interchangeable; weight wins if both are supplied.

Text-friendly shortcuts (7)

PropTypeEffect
italicbooleanfont-style: italic
align'left' | 'center' | 'right' | 'justify'maps to text-align
transform'none' | 'upper' | 'lower' | 'capitalize'maps to text-transform (upper/lower are friendly aliases for the CSS verbose forms)
decoration'none' | 'underline' | 'line-through'maps to text-decoration
truncatebooleanoverflow: hidden; text-overflow: ellipsis; white-space: nowrap;
lineClampnumbermulti-line clamp via the -webkit- flexbox combo; wins over truncate when both are set

Inherited from <Div />

Everything else: every CSS shorthand prop the Div accepts (m / p / bg / fg / radius / shadow / flex / gap / width / height / …), all 7 pseudo hooks (onHover, onFocusVisible, onActive, onDisabled, onChecked, onGroupHover, onDataState), polymorphism (as / actLike / asChild), responsive show / hide (hideOn / displayOn), centered, animation, the full sx prop, every HTML attribute, ref forwarding, and the className cascade — all inherited unchanged. See the Div docs for the full prop tables.

Style resolution order

Lowest-precedence first:

  1. Variant recipe class — text-4xl font-semibold leading-tight tracking-tight (from typographyRecipe).
  2. Div's recipe class — min-w-0 plus any hideOn / displayOn utilities.
  3. sx prop — engine sxToStyle resolution (palette / radius / spacing / shadow tokens).
  4. Div's curated CSS shorthand — m / p / bg / fg / etc., also via sxToStyle.
  5. Typography text-style chunk — the 5 token-resolved type props + the 7 shortcuts.
  6. Consumer style prop — always wins.

Consumer className is merged via tailwind-merge (so a later utility always overrides an earlier one — e.g. <Typography variant="body" className="text-primary" /> swaps the body color without touching the size / weight).

Examples

See examples/ — 13 files covering the variant ladder, headings vs body semantics, code spans, truncation + line clamp, alignment, weight (including a numeric escape hatch), italic + decoration + transform, polymorphism via actLike="a", the full token-size ladder, and the pseudo-state hooks.

Accessibility

  • The default variant → element mapping keeps the document outline correct out of the box. h1 through h6 render their semantic counterparts; body* variants are <p> (announced as paragraphs by AT); caption / overline are inline <span>s so they don't break the surrounding flow.
  • display collapses to <h1> semantically — use it for the page's primary visual hero only. If you want the visual without the semantics, pair it with as="div" or as="p".
  • align="justify" is preserved for consumer choice but discouraged for long-form copy on the web (the rivers degrade readability without manual hyphenation).
  • lineClamp truncates content invisibly — pair with a tooltip / disclosure when the full text matters to AT users.
  • The code variant ships the <code> element + mono font; for block code, wrap a <pre> around it (Typography is single-element by design).

RTL

The variant recipe never uses physical text-left / text-right; the align shortcut maps through text-align which respects the document direction. For directional padding around code / overline use the Div logical pairs (paddingInlineStart, paddingInlineEnd).

Theming

All five type-specific CSS vars (--sds-font-size-*, --sds-font-weight-*, --sds-line-height-*, --sds-letter-spacing-*, --sds-font-sans / --sds-font-mono / --sds-font-display) are emitted by themeToCssVars from the typography token shape. Override them per-variant or per-theme via the existing theme overrides — no Typography-side change is needed.

The display face

display and h1–h6 render in --sds-font-display; body and supporting variants render in --sds-font-sans; code renders in --sds-font-mono. So a brand that pairs a serif display face with a sans body face sets one token and the whole heading hierarchy follows:

ts
defineTheme({
  typography: {
    fontFamily: {
      display: '"Playfair Display", Georgia, serif',
      sans: '"Source Sans 3", ui-sans-serif, system-ui, sans-serif',
    },
  },
});
defineTheme({
  typography: {
    fontFamily: {
      display: '"Playfair Display", Georgia, serif',
      sans: '"Source Sans 3", ui-sans-serif, system-ui, sans-serif',
    },
  },
});

typography.fontFamily.display is optional and unset by default. Every reference to it carries a fallback — var(--sds-font-display, var(--sds-font-sans)) — so a theme that never sets it renders headings in the body face, exactly as it did before the slot existed. Leaving it unset (rather than defaulting it to a copy of the sans stack) is deliberate: it means headings track --sds-font-sans wherever the cascade changes it, including the default variant's Apple platform overlay.

Note the DS ships no webfonts — always pass a complete stack with real system fallbacks.

Bundle

<Typography /> is implemented as a thin wrapper over <Div />. The only new code is the 13-row variant recipe, the variant → element map, the 5-row token table + resolver, and the three shortcut maps (align / transform / decoration). Per-instance bundle cost is dominated by <Div />; Typography itself adds ~3 kB minified before gzip and is fully tree-shakeable.

Do / Don't

  • Do lean on variants for the common 95% (page titles, body copy, captions, code spans).
  • Do reach for fontSize / weight / lineHeight / letterSpacing / fontFamily props when a one-off needs a non-variant tweak.
  • Do use truncate / lineClamp on text inside fixed-width containers.
  • Don't stack a variant="h1" inside another variant="h1" — variants control both the visual and the semantic. If you need a visually large piece of text inside a heading, override with as="span" to keep the outer document outline correct.
  • Don't override fontFamily per-instance unless you really need to — let the theme set the family globally and reach for the prop only at exceptional surfaces.
  • Don't hand-set fontFamily="display" on every heading. The heading variants already do it; the prop is for the exceptions (a display face on a price, a stat, a step number).

Examples

Align

Loading preview…
Align.tsx

AsAnchor

Loading preview…
AsAnchor.tsx

Basic

Loading preview…
Basic.tsx

Body

Loading preview…
Body.tsx

Code

Loading preview…
Code.tsx

Headings

Loading preview…
Headings.tsx

Italic

Loading preview…
Italic.tsx

LineClamp

Loading preview…
LineClamp.tsx

Pseudo

Loading preview…
Pseudo.tsx

TokenSizes

Loading preview…
TokenSizes.tsx

Truncate

Loading preview…
Truncate.tsx

Variants

Loading preview…
Variants.tsx

Weight

Loading preview…
Weight.tsx

Props

PropTypeDefaultDescription
actLikeElementType—Alias of `as`. Provided because the requested API uses `actLike="button"` reading. When both `as` and `actLike` are set, `actLike` wins and a dev warning fires.
alignenum—Shortcut for `textAlign`. Friendly key set.
alignContentAlignContent——
alignItemsAlignItems——
alignSelfAlignSelf——
altstring—Media `alt`.
animateOnViewboolean | ViewportOptions—Defer `animation` until the element scrolls into view, instead of running it on mount. Without this, every animated element on a page finishes its entrance before the user has scrolled to it — so a long marketing page animates entirely off-screen and reads as static. Pass `true` for the DS defaults (`once: true`, `amount: 0.25`, and a `-64px` bottom margin so the reveal starts just before the element reaches the fold), or an object to tune them. Ignored when `animation` is absent, when `asChild` is set, and under reduced motion — where the element renders plain and fully visible rather than waiting for a trigger it will never receive. @example <Div animation="riseIn" animateOnView /> <Div animation="fadeIn" animateOnView={{ once: false, amount: 0.5 }} />
animationenum—Animation preset (`fadeIn`, `scaleIn`, `slideInFromBottom`, `slideInFromTop`, `pressScale`). When set, the element renders through `motion.create(...)` with the matching variant. `useReducedMotion()` short-circuits the wrapper so reduced-motion users get a plain element. Skipped when `asChild` is true.
animationDelaynumber—Seconds to wait before the animation starts. Composes with `stagger` on an ancestor.
animationDurationnumber | "normal" | "fast" | "slow" | "slower" | "deliberate"—Animation length — seconds, or a motion token name (`'fast'` · `'normal'` · `'slow'`). Token names resolve through `@apx-ui/tokens`, so a theme-level motion change reaches here.
animationEasestring—Easing — a token name (`'standard'` · `'emphasized'` · `'decelerate'` · `'accelerate'` · `'linear'`) or any raw CSS easing string.
asElementType—Render element. Defaults to `'div'`.
asChildboolean—Radix-style polymorphism — merges Div's props onto the single child element. Mutually exclusive with `as` / `actLike`; `asChild` wins on conflict (dev warning fires).
aspectRatioAspectRatio——
backdropFilterBackdropFilter——
backgroundBackground<string | number>——
backgroundColorstring | (string & {})——
backgroundImageBackgroundImage——
bgstring | (string & {})——
borderBorder<string | number>——
borderBottomBorderBottom<string | number>——
borderColorstring | (string & {})——
borderLeftBorderLeft<string | number>——
borderRadiusBorderRadius<string | number>——
borderRightBorderRight<string | number>——
borderStyleBorderStyle——
borderTopBorderTop<string | number>——
borderWidthBorderWidth<string | number>——
bottomBottom<string | number>——
boxShadowstring | (string & {})——
boxSizingenum——
centeredboolean—Shortcut for `display: flex; align-items: center; justify-content: center;`. Explicit style props win — if any of the three keys is also supplied, the consumer value is kept.
checkedboolean—Form control `checked`.
childrenReactNode—Children to render inside the element (or the single child when `asChild` is true).
classNamestring—Standard className. Appended after the recipe + pseudo classes via `tailwind-merge`.
colorstring | (string & {})——
columnGapColumnGap<string | number>——
cursorCursor——
decorationenum—Shortcut for `textDecoration`.
decorativeboolean—Shortcut for the "decorative overlay" pattern — fills the parent (`position: absolute; inset: 0;`), declines pointer events, and adds `aria-hidden="true"` so screen readers skip the purely visual layer. Compose with `gradient` for the soft backdrop pattern, or use it standalone with a custom `backgroundImage` / `className`.
disabledboolean—Form control `disabled`.
displayDisplay——
displayOnenum—Start hidden, reveal the element at the named breakpoint and above.
downloadstring | boolean—Anchor `download`.
fgstring | (string & {})——
filterFilter——
flexFlex<string | number>——
flexBasisFlexBasis<string | number>——
flexDirectionenum——
flexGrowFlexGrow——
flexShrinkFlexShrink——
flexWrapenum——
fontFamily(string & {}) | TypographyFontFamily—Token (`'sans'` / `'mono'`) or any raw CSS font-family stack.
fontSizenumber | TypographyFontSize | (string & {})—Token (`'xs'`–`'5xl'`) or any raw CSS font-size value.
fontWeightnumber | (string & {}) | TypographyWeight—Canonical name — also accepted. Token (`'normal'`–`'bold'`) or any raw CSS value.
gapGap<string | number>——
gradientDivGradient—Theme-aware background gradient — replaces the verbose `className="bg-[radial-gradient(...)]"` recipe with a single typed prop. - `true` → emit a default radial gradient using the active palette (`primary.subtle` → `transparent`, anchored top-left). Tracks the active theme variant for free. - `DivGradientConfig` object → tweak the gradient (`type`, `from`, `to`, `position`, `size`, `fromStop`, `toStop`). `from` / `to` accept palette token paths (`'success.subtle'`) or any raw CSS color. - `string` → escape hatch — used verbatim as `background-image` (drop in any `radial-gradient(...)` / `linear-gradient(...)` / `url(...)`). Sits in the inline style stack just **above** `sx` and just **below** the curated style props, so explicit `backgroundImage` / `background` overrides still win. Often paired with `decorative` for the "soft backdrop" pattern: <Div decorative gradient /> // theme default <Div decorative gradient={{ position: 'top' }} /> // override one field
gridAreaGridArea——
gridAutoColumnsGridAutoColumns<string | number>——
gridAutoFlowGridAutoFlow——
gridAutoRowsGridAutoRows<string | number>——
gridColumnGridColumn——
gridRowGridRow——
gridTemplateColumnsGridTemplateColumns<string | number>——
gridTemplateRowsGridTemplateRows<string | number>——
hHeight<string | number>——
heightHeight<string | number>——
hideOnenum—Hide the element at the named breakpoint and above (Tailwind "from upward" semantics).
hrefstring—Anchor `href` — narrow when using `as="a"` / `actLike="a"`.
htmlForstring—Label `htmlFor`.
insetInset<string | number>——
italicboolean—Shortcut for `fontStyle: 'italic'`.
justifyContentJustifyContent——
justifyItemsJustifyItems——
justifySelfJustifySelf——
leftLeft<string | number>——
letterSpacing(string & {}) | TypographyLetterSpacing—Token (`'tighter'`–`'wider'`) or any raw CSS letter-spacing value.
lineClampnumber—Multi-line ellipsis. Renders as `display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: N; overflow: hidden;`. Pass the maximum number of visible lines.
lineHeightnumber | (string & {}) | TypographyLineHeight—Token (`'none'`–`'relaxed'`) or any raw CSS line-height value.
mMargin<string | number>——
marginMargin<string | number>——
marginBlockMarginBlock<string | number>——
marginBottomMarginBottom<string | number>——
marginInlineMarginInline<string | number>——
marginLeftMarginLeft<string | number>——
marginRightMarginRight<string | number>——
marginTopMarginTop<string | number>——
maxHeightMaxHeight<string | number>——
maxWidthMaxWidth<string | number>——
mbMarginBottom<string | number>——
minHeightMinHeight<string | number>——
minWidthMinWidth<string | number>——
mlMarginLeft<string | number>——
mrMarginRight<string | number>——
mtMarginTop<string | number>——
mxMarginInline<string | number>——
myMarginBlock<string | number>——
namestring—Form field `name`.
onActivestring—Tailwind classes applied on `:active` (pressed). e.g. `"scale-[0.98]"`.
onCheckedstring—Tailwind classes applied when `aria-checked="true"`.
onDataStatestring—Tailwind classes applied when `data-state="open"` is present.
onDisabledstring—Tailwind classes applied on `:disabled`. e.g. `"opacity-50 cursor-not-allowed"`.
onFocusVisiblestring—Tailwind classes applied on `:focus-visible` (keyboard focus). e.g. `"ring-2 ring-primary-500"`.
onGroupHoverstring—Tailwind classes applied when a parent `.group` is hovered.
onHoverstring—Tailwind classes applied on `:hover`. e.g. `"bg-primary-100 scale-[1.02]"`.
opacityOpacity——
orderOrder——
overflowOverflow——
overflowXenum——
overflowYenum——
pPadding<string | number>——
paddingPadding<string | number>——
paddingBlockPaddingBlock<string | number>——
paddingBottomPaddingBottom<string | number>——
paddingInlinePaddingInline<string | number>——
paddingLeftPaddingLeft<string | number>——
paddingRightPaddingRight<string | number>——
paddingTopPaddingTop<string | number>——
pbPaddingBottom<string | number>——
plPaddingLeft<string | number>——
placeContentPlaceContent——
placeItemsPlaceItems——
placeSelfPlaceSelf——
pointerEventsenum——
positionenum——
prPaddingRight<string | number>——
ptPaddingTop<string | number>——
pxPaddingInline<string | number>——
pyPaddingBlock<string | number>——
radiusBorderRadius<string | number>——
refRef<HTMLElement>—Ref to the rendered element. Type depends on `as` / `actLike` / `asChild`. Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref). @see {@link https://react.dev/learn/referencing-values-with-refs#refs-and-the-dom React Docs}
relstring—Anchor `rel`.
rightRight<string | number>——
rowGapRowGap<string | number>——
shadowstring | (string & {})——
sizeenum—The **visual scale only**, with no element attached. `variant` drives two things — the type scale *and* the rendered element — so the most natural way to ask for a size makes a semantic promise you never meant: ```tsx <Typography variant="h4">{clientName}</Typography> // emits a real <h4> ``` That shipped an `h1 → h4` skip and eight phantom subheadings on a page whose "headings" were a list of company names. Nothing showed it: the file reads correctly, the design is right, the tests pass. It is visible only in the rendered outline. So `size` is the same scale with the promise removed. It renders a `<span>` unless `as` says otherwise, and the rule is short enough to remember: > **`variant` makes a semantic promise. `size` doesn't.** ```tsx <Typography size="h4">{clientName}</Typography> // h4's scale, no heading <Typography variant="h4">{sectionTitle}</Typography> // an actual h4 ```
srcstring—Media `src`.
staggernumber—Cascade descendant `<Div animation="…">` elements instead of firing them together: the number of seconds between each one starting. The children need no extra props — they opt in simply by having an `animation`. Combine with `animateOnView` on this element to make the whole group reveal on scroll as one unit, which is the common case for a card grid or a feature list. @example <Div stagger={0.08} animateOnView> {items.map((i) => <Div key={i.id} animation="riseIn">…</Div>)} </Div>
staggerDelaynumber—Seconds to wait before the first staggered child starts. Requires `stagger`.
styleCSSProperties—Restate consumer style override — wins over the Typography-specific style chunk.
sxSx—Theme-aware inline style (resolves palette / spacing / radius tokens).
targetstring—Anchor `target`.
textOverflowTextOverflow——
topTop<string | number>——
transformenum—Shortcut for `textTransform`. `'upper'` / `'lower'` are aliases for `'uppercase'` / `'lowercase'`.
transitionTransition<string & {}>——
truncateboolean—Single-line ellipsis. Injects `overflow: hidden; text-overflow: ellipsis; white-space: nowrap;`.
typestring—Button `type` — narrow when using `as="button"` / `actLike="button"`.
userSelectenum——
valuestring | number | readonly string[]—Form field `value`.
variantenum—Visual + semantic variant. Default `'body'`.
visibilityenum——
wWidth<string | number>——
weightnumber | (string & {}) | TypographyWeight—Friendly alias for `fontWeight`. Same token table; takes precedence over `fontWeight` if both supplied.
whiteSpaceWhiteSpace——
widthWidth<string | number>——
wordBreakenum——
zZIndex——
zIndexZIndex——