# Typed text

The app's own words (a heading, an empty state, a first-run greeting) typed out once as the page first draws, when the brand turns it on with the Pro motion-drawings item's `--cd-show-typing: type`. It is motion for show: the whole text is in the page from the start, read by screen readers and found by search, with the part not yet typed drawn transparent in its place, so nothing moves as it types and nothing is hidden from assistive technology. It types at about 30 ms a character, 900 ms at most in all, only inside the page's first-draw window (a heading that appears later, after a filter or a tab, is simply there), and never under reduced motion, `data-motion="calm"` or `"none"`, or at the Off level. A press, a key or a focus anywhere finishes it at once.

Never use it for a model's reply: a reply arrives in pieces already, and `StreamingText` draws those pieces as they come. Without the Pro item, or without the brand's value, it is plain text.

- Registry name: `typed-text` (`@candor/typed-text`)
- Tier: Pro. Installing it needs a Pro, Premium or Team licence key: the person runs `npx candor-ui key <key>` themselves; never ask for the key in chat or write it to a file.
- Docs: https://candor.themethodic.com/docs/typed-text

## Install

```bash
npx candor-ui add typed-text
```

Run `npx candor-ui@latest init` once first (https://candor.themethodic.com/get-started.md). Without the CLI: `npx shadcn@latest add @candor/typed-text`.
It brings in: motion, tokens, utils.
npm packages: @base-ui/react@^1.9.0.

## Example

```tsx
"use client"

import { TypedText } from "@/components/candor/typed-text"

/*
 * Plain text until the brand turns it on with the Pro motion-drawings item (`--cd-show-typing: type` on :root); then the
 * heading types once as the page first draws. The whole heading is in the page from the start. A model's reply never
 * goes here: use StreamingText, which draws its pieces as they arrive.
 */
export default function Example() {
  return (
    <div className="flex flex-col gap-1">
      {/* `render` draws it as any element, as the kit's other parts take it; `as="h2"` does the same for a few tags. */}
      {/* oxlint-disable-next-line jsx-a11y/heading-has-content -- TypedText gives the heading its words */}
      <TypedText render={<h2 />} className="text-lg font-semibold" text="Welcome back, here is what changed while you were away" />
      <p className="text-sm text-muted-foreground">Three runs finished and one needs you.</p>
    </div>
  )
}
```

## <TypedText>

Props:

- `text: string`: The app's own words. Never a model's or another site's text.
- `as?: "span" | "p" | "h1" | "h2" | "h3" | undefined` (default `"span"`): The element it is: `span` (the default), `p`, `h1`, `h2` or `h3`. `render` does the same for any element.
- `render?: useRender.RenderProp | undefined`: The element to draw it as, as the kit's other parts take it: `render={<h2 className="…" />}`, or a function given the props. The text is its children; `data-slot` and the typing state stay on it. Given, it wins over `as`.
- `className?: string | undefined`: Classes, merged with Candor's.

## Terms used here

- **Calm level**: What Candor's motion does for a person whose operating system asks for reduced motion: the highest-precedence setting, above the app's own motion level (`none`, `calm`, `subtle` or `expressive`) and the brand file. A theme tunes how a change looks, never when it happens, so nothing depends on seeing the motion. (https://candor.themethodic.com/glossary.md#calm-level)

## Rules for using Candor UI

- Components take plain typed data. Never pass model output as HTML or render it as a link; messages are typed blocks.
- A control that can't be used says why: wrap it in `<Locked reason="…">`, don't just disable it.
- Don't show a value you don't have: leave it out (it renders as —) rather than guess. An estimate is labelled as one.
- Nothing is pre-selected in a decision a person makes, and the agent is named from your app's data, never from model output.
- Your app's words go in `LocaleProvider`: its fixed strings in `strings`, its nouns in `nouns`; entity kinds and agent roles in `EntityKindsProvider` and `AgentRolesProvider`.
