Text
Text renders body copy from the tokens only: size sets a --text-*
step (font size and line height together), weight a --font-weight-*
token, tone a semantic colour and the muted boolean de-emphasis. Nothing hardcodes a pixel size, so a
type-scale retheme moves every paragraph.
import Text from '@zuilib/primitives/text'
Sizes and weights
xs, sm, md and lg are the body range of the scale; md is
--text-base.
Tones
neutral is --foreground. The status tones read --danger-text,
--success-text and --warning-text: the status colours made legible on
--background. Every tone meets WCAG AA (4.5:1) on --background in both
themes. De-emphasis is not a tone: the muted boolean
(--muted-foreground) is orthogonal, and wins the colour when both are
set.
Truncate and line clamp
truncate is a single line with an ellipsis; on an inline tag it adds
inline-block max-w-full so there is a box to overflow. lineClamp clamps
to that many lines and wins over truncate; the count goes through
--text-line-clamp, so any positive integer works without a matching class.
As a label
as="label" renders a bare <label> with the typography props and
requires htmlFor, so it is always associated with a control. It does not
join a Headless UI Field; for a form label that wires itself to the
control (and carries required / unsaved markers) use Label.
Props
TextProps<TTag> extends the attributes of the rendered tag with:
| Prop | Type | Default | Description |
|---|---|---|---|
as | 'p' | 'span' | 'div' | 'label' | 'p' | label requires htmlFor; the ref is typed from as |
size | 'xs' | 'sm' | 'md' | 'lg' | 'md' | --text-* step; md is --text-base |
weight | 'normal' | 'medium' | 'semibold' | 'bold' | 'normal' | --font-weight-* |
tone | 'neutral' | 'success' | 'warning' | 'danger' | 'neutral' | Status tones use the --*-text tokens |
muted | boolean | false | De-emphasised (--muted-foreground); orthogonal to tone and wins the colour when both are set |
truncate | boolean | false | Single line with ellipsis; ignored when lineClamp is set |
lineClamp | number | — | Positive integer; other values are ignored |
htmlForrequired | string | — | Only with as="label"; rejected on other tags |
className | string | — | Merged last, after the size, weight and tone classes |
Slots
| Slot | Element | Notes |
|---|---|---|
[data-slot="text"] | p (or as) | Root. Also data-size, data-weight, data-tone, data-muted, data-truncate, data-line-clamp |
/* Consumer CSS: italic muted copy */
[data-slot="text"][data-muted] {
font-style: italic;
}
Tokens
| Token | Used for |
|---|---|
--text-xs, --text-sm, --text-base, --text-lg | Size and line height per size |
--font-weight-normal/medium/semibold/bold | weight |
--foreground, --muted-foreground | neutral and muted |
--danger-text, --success-text, --warning-text | Status tones, AA on --background |
Accessibility
- Renders a plain semantic tag; no roles or aria are added.
- Every colour tone meets WCAG AA (4.5:1) on
--backgroundin both themes. The surface tokens (--success,--warning,--danger) are never used as text colour, and there is no dimmer-than-mutedoption because--muted-foregroundsits at the AA floor on the light theme. as="label"requireshtmlForat the type level, so a label is always associated with its control.- Truncated or clamped text is still fully present in the DOM for assistive tech; add a
titleor tooltip if sighted users need the full value.
Related
- Heading: the same scale for
h1–h6. - Label and FieldDescription: form text that joins a
Field. - Theming: the type scale and
--*-texttokens.