# Typography Components

> Generated reference (regen-owned; see [index.md](index.md)). Binds only under `primitives: nurix`.

Import each from its layered subpath, e.g. `import { Chip } from "@nurix/components/element/chip"`.

## Chip

THE small label: tag, filter token, enum value, status pill. A Chip with no `onRemove` renders no interactive descendant, so it is a safe pure-display label (`@nurix/components/element/chip`).

**Props:** `variant` [default|secondary|outline|muted|soft|ghost|bare|status|colored], `intent` [neutral|info|success|warning|danger] (exclusive with `color`), `color` (a stored data colour), `size` [sm|default|lg], `rounded` [low|medium|high], `prefix` ["dot"|node], `isPulsing`, `onRemove`, `disabled`, `isTruncated` (default true), `isInteractive`, `labels` {remove}, `render`

Status meaning is `intent`, never `color="var(--intent-success)"`. `color` repaints the chrome only on `variant="colored"` (the resolved variant when `color` is set without one); on other variants it reaches only a `prefix="dot"`. `isPulsing` animates nothing without `prefix="dot"`. Drop `onRemove` when `render` makes the chip itself a link or button. A toggling chip is `compound/reaction`, not this.

```tsx
<Chip variant="outline" size="sm" onRemove={() => remove(id)}>React</Chip>
<Chip variant="status" prefix="dot" isPulsing intent="info">Connecting</Chip>
```

## Stat

One KPI unit (`element/stat`): value and label on a line, an optional sub line beneath. It owns the unit, never the ledger row — lay several on a `Row` at the call site.

**Props:** `label:string`, `value:string` (format the number and its unit first), `sub?`, `intent` [neutral|info|success|warning|danger] (paints the value from the `--intent-*` tokens; default `neutral` inherits), `href` (renders an anchor), `onClick` (renders a button; with `href` it runs before navigation), `action` (inline affordance after the label — plain form only, the type rejects it beside `href`/`onClick`), `render` (a router link: `render={<RouterLink to="/breached" />}`)

- The anchor and button forms take no margin: their hover wash paints on an outset pseudo-element, and a clipping parent cuts it.
- A dashboard stat tile with trend, comparison or a visual is the `stat` spec of `Chart` (`block/chart`), documented in [charts](charts.md).

```tsx
<Row align="start" gap="lg" className="justify-end border-t pt-4">
  <Stat label="Open" value="128" sub="across 4 queues" />
  <Stat label="Breached" value="7" intent="danger" href="/breached" />
</Row>
```

## CodeBlock

Highlighted block code through shiki: line numbers, diff rows, emphasis, collapse, wrap, folding, line selection and streaming (`@nurix/components/compound/code-block`). Requires the optional peer `shiki` (the `code` family) installed before the subpath is imported at all, even for `hasHighlighting={false}`.

**Sub-components:** `CodeBlock.Header`, `CodeBlock.Title`, `CodeBlock.Language`, `CodeBlock.CopyButton`, `CodeBlock.DownloadButton`, `CodeBlock.WrapToggle`, `CodeBlock.ExpandButton`, `CodeBlock.LineActions`, `CodeBlock.Content`

**Props:** `value` or `lines` (pre-tokenized, exclusive), `language`, `hasHighlighting` (default true), `hasLineNumbers`, `startLine`, `diff` {added, removed}, `emphasizedLines`, `emphasizedWords`, `focusedLines`, `lineIntents` {danger, warning, info}, `maxLines` + `open`/`defaultOpen`, `wrap`/`defaultWrap`, `isFoldable`, `isSelectable`, `isStreaming`, `variant` [default|bare], `themes`, `label`, `labels`

**Helpers:** `highlightCode(value, options)` (a server component awaits it and passes `lines`), `parseUnifiedDiff(patch)` (per-file `lines` for a `git diff`), `ansiToLines(text)` (terminal output), `markdownFences` / `markdownCodeProps` (split a markdown string by hand)

Line specs are `"2-4,7"` or `[2, 3, 4, 7]` and need a resolved `language`; an unknown `language` paints plain lines. Highlighting is asynchronous, so plain lines paint first. The header is `flex`, so give the trailing part `ml-auto`. Inline code in a sentence is `element/code`; a markdown string with fenced code is `element/markdown`.

```tsx
<CodeBlock value={snippet} language="tsx" hasLineNumbers diff={{ removed: [2], added: [3] }}>
  <CodeBlock.Header>
    <CodeBlock.Title>app.tsx</CodeBlock.Title>
    <CodeBlock.Language className="ml-auto" />
    <CodeBlock.CopyButton />
  </CodeBlock.Header>
</CodeBlock>
```

## SecureText

Masked display for a secret (API key, card number) with an optional reveal toggle (`@nurix/components/element/secure-text`). A secret being typed is `element/input` with `type="password"`, not this.

**Props:** `value`, `hasRevealButton` (default true), `defaultRevealed`, `revealed`/`onRevealedChange` (controlled), `maskOptions` (`{ maskChar, unmaskedStart, unmaskedEnd, preserveSpacing, grouping, showLength }`), `labels` {reveal, hide, masked}, `fallback` (empty value, no toggle)

It takes no `size` and no `variant`: it inherits the surrounding text, so wrap it in `<Code variant="bare">` for monospaced digits. `maskText(value, options)` masks a value in a cell, tooltip or log line without the toggle. The full `value` reaches the client, so masking is presentation, never protection.

```tsx
<SecureText
  value={apiKey}
  maskOptions={{ unmaskedStart: 3, unmaskedEnd: 4 }}
  labels={{ reveal: "Reveal API key", hide: "Hide API key" }}
/>
```

## Timestamp

A living instant in a `<time>` element: relative near now, absolute beyond a threshold, with the exact time on `title` (`@nurix/components/element/timestamp`).

**Props:** `value` (Date | ms), `relativeThreshold` (default `DEFAULT_RELATIVE_THRESHOLD`, 30 days; `0` always absolute, `Infinity` always relative), `format` (an `Intl` field-option patch over month/day/year; name a field `undefined` to drop it), `locale`, `isLive` (default true), `title` (`""` writes none), `titleFormat`, `fallback`, `render` (function form for custom copy; no `children`)

The label reads absolute until hydration, so server and client markup agree. A date being picked is `compound/date-picker`; a never-live, never-relative string is a plain `date-fns` `format` call.

```tsx
<Timestamp value={event.createdAt} fallback="—" />
```

## Text and headings

No text or heading component exists: write the semantic element (`<h2>`, `<p>`, `<span>`) and pick a step of the shipped type ramp through its utility — `text-display`, `text-title`, `text-h1`, `text-h2`, `text-h3`, `text-prose`, `text-body`, `text-dense`, `text-meta`, `text-micro`, `text-code` (each carries size, line height and weight). The library ships no font family, so text inherits the product's face; line up digits with `tabular-nums`, never `font-mono`.

## Other Components

- `element/code` — `Code`, `codeVariants`: inline `<code>` sized at the surrounding text (no `size`), no highlighting; `variant` [default|bare] (`bare` inside a host unless explicit), `render`
- `element/kbd` — `Kbd`, `Kbd.Group`: em-sized keycap (no `size`); `variant` [default|outline] (`outline` on a muted surface such as a search trigger), `label` (spoken name for a glyph key like `⌘`; never `aria-label`); `Kbd.Group` adds spacing, no `+` separator
- `element/label` — `Label`: native `<label>` bound by `htmlFor`; `disabled` dims it via `data-disabled`, `render` swaps the element (inside a `Cell`, use `Cell.Label`)
- `element/link` — `Link`, `linkVariants`: navigational anchor that inherits the type around it; `variant` [default|muted|plain|underline], `isExternal` (or `target="_blank"`: hardened `rel`, trailing icon, announced "(opens in a new tab)"), `isActive` (`aria-current="page"`), `disabled`, `labels` {newTab}, `render` (a router link element); an action is Button `variant="link"`
- `element/markdown` — `Markdown`: read-only GFM render of a string (`children`) with raw HTML escaped; fenced code is an unhighlighted muted block; restyle through `--doc-*` tokens on the root, never `[&_p]:` utilities; `labels` {footnotes, footnoteBackReference}, `render`. Requires the optional peers `react-markdown` + `remark-gfm` (the `markdown` family)
