lensclear design system

Typography by variant, for every text node.

Overview

Use Text for any text node, never a div with classes. You say what the text is; the component decides how it looks.

Each prop sits on one axis. variant is the role (family, size, weight, leading, tracking), color is the tone, as is the element. Orthogonal modifiers layer on without touching the role: monospace, tabularNums, truncate, lineThrough, and a formatter for numbers. Colors resolve light and dark on their own, and loading renders a skeleton with no extra markup.

Text has no className and no style. Size, weight, color, and leading are owned by the props above, so compose layout and spacing with a Box around Text.

Variants

Each variant is a typographic role. The token name sits above each sample.

displayThe quick brown fox
heading-lThe quick brown fox
page-titleThe quick brown fox
valueThe quick brown fox
heading-sThe quick brown fox
heading-xsThe quick brown fox
leadThe quick brown fox
body-lThe quick brown fox
bodyThe quick brown fox
smallThe quick brown fox
labelThe quick brown fox
captionThe quick brown fox
<Text variant="page-title">Page title</Text>
<Text variant="body">Comfortable reading copy.</Text>
<Text variant="label">Field label</Text>

Monospace

monospace is a boolean, not a variant. It swaps in the mono family and keeps the size and weight, so any text can be monospaced.

variant="value" monospacebun add @clear-labs/lens
variant="body" monospacebun add @clear-labs/lens
variant="small" monospacebun add @clear-labs/lens
variant="label" monospacebun add @clear-labs/lens
<Text variant="value" monospace>404</Text>
<Text variant="body" monospace>bun add @clear-labs/lens</Text>
<Text variant="label" monospace>CLEAR_TOKEN</Text>

Formatting

Pass a raw value as children and a formatter to render it. Formatting lives in the component, so call sites never hand-roll toLocaleString. Add tabularNums to line figures up.

3290033
3,290,0333.3M
48200
48,20048K
1500
1,5001.5K
42
4242
<Text variant="value" formatter="number">{3290033}</Text>
<Text variant="body" formatter="compact">{3290033}</Text>
<Text formatter={(v) => `$${v}`}>{42}</Text>

Truncation

truncate owns the overflow css. true clamps to one line, a number clamps to that many lines.

truncate

lens is the clear design system: tokens, primitives, and the components stable-app builds its surfaces from.

truncate={2}

lens is the clear design system: tokens, primitives, and the components stable-app builds its surfaces from.

<Text variant="body" truncate>One line, then an ellipsis</Text>
<Text variant="body" truncate={2}>Clamped to two lines</Text>

Colors

Tone by name. inverse is shown on a foreground surface.

default
Sample text in this color
muted
Sample text in this color
primary
Sample text in this color
accent
Sample text in this color
success
Sample text in this color
warning
Sample text in this color
danger
Sample text in this color
inverse
Sample text in this color
<Text color="muted">De-emphasised copy</Text>
<Text color="primary">The action ink</Text>
<Text color="success">Saved</Text>
<Text color="danger">Something went wrong</Text>

States

loading renders a skeleton, single or multi-line. lineThrough strikes the content.

loading

Loading a single line of text

loading, placeholderNumberOfLines=3

lineThrough

Previous price

<Text loading placeholderText="Loading a single line of text" />
<Text loading placeholderNumberOfLines={3} />
<Text lineThrough color="muted">Previous price</Text>

Best practices

Typographic decisions stay inside Text. Pick the role and the tone; the component owns the rest.

Do

  • +Pick a variant for the role. Never a size.
  • +Set as on headings so the outline is right. Size and level are independent.
  • +Use color inherit to take a parent Box color, for hover and active states.
  • +Pass raw numbers with a formatter. Add tabularNums when figures sit in a column.
  • +Compose layout and spacing with a Box around Text.

Avoid

  • -No class for size, weight, color, or leading. Text has no className.
  • -No hierarchy by size alone. An h2 can take any variant.
  • -No toLocaleString before Text. The formatter keeps output consistent and safe to hydrate.
  • -No layout containers inside Text. Children are text and inline content.
  • -No heading variant for emphasis. Use the right variant, monospace, or a color.

Props

variantTextVariantdefault: 'body'

display, heading-l, page-title, value, heading-s, heading-xs, lead, body-l, body, small, label, caption.

colorTextColordefault: 'default'

default, muted, inverse, success, warning, danger, accent, primary, inherit.

asEdefault: inferred from variant

The element. Headings render h1 to h3, label and caption span, the rest p. Override for the right outline. Dom props are forwarded.

monospacebooleandefault: false

The monospace family at the size and weight the variant sets. Pair with any variant.

formatterTextFormatter

Formats the children value. 'number' adds grouping separators (3,290,033), 'compact' shortens (3.3M), a function does anything else. Pass the raw value as children.

tabularNumsbooleandefault: false

Tabular figures, so numbers line up in a column. For tables and readouts.

truncatenumber | booleandefault: false

true clamps to one line with an ellipsis; a number clamps to that many lines.

Text alignment.

Wrapping. Headings default to balance, body copy to pretty.

loadingbooleandefault: false

A pulsing skeleton instead of children.

placeholderTextstring

Sizes the single-line skeleton. Falls back to children, then Loading...

placeholderNumberOfLinesnumberdefault: 1

Above 1, a multi-line skeleton.

lineThroughbooleandefault: false

A line-through decoration.