> ## Documentation Index
> Fetch the complete documentation index at: https://anvil.servicetitan.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Text - Web (AI Kit)

> Text displays typographic content with Carto styles.

> [!NOTE]
>
> For development, import `Text` from
> `@servicetitan/anvil2-ai-kit`. For design, find it in the
> [AI Kit Web Component Library file](https://www.figma.com/design/QEIsArLktLeJAaFvcpw3PO/AI-Kit-Web-Component-Library).

ai-kit-text

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-text?file=src/App.tsx)

```tsx lines theme={null}
import { Text } from "@servicetitan/anvil2-ai-kit";

function App() {
  return <Text text="The quick brown fox jumps over the lazy dog." />;
}

export default App;
```

## Options

Text supports three variants — headline, body, and eyebrow — each with its own size scale, plus a highlight treatment that works across all three.

### Headline

ai-kit-text-headline-sizes

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-text-headline-sizes?file=src/App.tsx)

```tsx lines theme={null}
import { Text } from "@servicetitan/anvil2-ai-kit";

function App() {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
      <Text variant="headline" el="h2" size="hero" text="Headline — hero" />
      <Text variant="headline" el="h2" size="major" text="Headline — major" />
      <Text
        variant="headline"
        el="h2"
        size="substantial"
        text="Headline — substantial"
      />
      <Text
        variant="headline"
        el="h2"
        size="regular"
        text="Headline — regular"
      />
    </div>
  );
}

export default App;
```

`el` sets the rendered heading tag (`h1`–`h6`) and is required whenever `variant="headline"` — a headline always commits to a semantic level. `size` picks the visual scale independently of `el`, so a page can use `h2` for document structure while sizing it `hero` for emphasis.

| Size | Value |
| - | - |
| Regular | 16px |
| Substantial | 20px |
| Major (default) | 24px |
| Hero | 32px |

### Body

ai-kit-text-body-sizes

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-text-body-sizes?file=src/App.tsx)

```tsx lines theme={null}
import { Text } from "@servicetitan/anvil2-ai-kit";

function App() {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
      <Text size="featured" text="Body — featured: the quick brown fox" />
      <Text size="regular" text="Body — regular: the quick brown fox" />
      <Text size="compact" text="Body — compact: the quick brown fox" />
      <Text size="fine" text="Body — fine: the quick brown fox" />
    </div>
  );
}

export default App;
```

Body is the default variant — omit `variant` for a `<p>`. `size` picks the scale.

| Size | Value |
| - | - |
| Fine | 12px |
| Compact | 14px |
| Regular (default) | 16px |
| Featured | 18px |

#### Inline

ai-kit-text-inline

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-text-inline?file=src/App.tsx)

```tsx lines theme={null}
import { Text } from "@servicetitan/anvil2-ai-kit";

function App() {
  return (
    <div>
      <Text inline text="Inline body fragment, " />
      <Text inline size="featured" text="featured-size inline, " />
      <Text inline size="compact" text="and a compact inline." />
    </div>
  );
}

export default App;
```

`inline` renders body text as a `<span>` instead of a `<p>`, so a fragment composes on the same line as surrounding content — useful for nesting `Text` inside running copy or inside another `Text`.

### Eyebrow

ai-kit-text-eyebrow

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-text-eyebrow?file=src/App.tsx)

```tsx lines theme={null}
import { Text } from "@servicetitan/anvil2-ai-kit";

function App() {
  return <Text variant="eyebrow" text="Section label" />;
}

export default App;
```

Eyebrow is a small, uppercased overline for section labels. It has a single fixed size (10px) — `size` isn't configurable on this variant.

### Highlighted

ai-kit-text-highlighted

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-text-highlighted?file=src/App.tsx)

```tsx lines theme={null}
import { Text } from "@servicetitan/anvil2-ai-kit";

function App() {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
      <Text
        variant="headline"
        el="h2"
        size="major"
        highlighted
        text="Revised headline"
      />
      <Text highlighted text="Revised body copy" />
      <Text variant="eyebrow" highlighted text="Revised label" />
      <div>
        <Text inline text="Partial inline " />
        <Text inline highlighted text="highlight" />
      </div>
    </div>
  );
}

export default App;
```

`highlighted` applies the suggested-change treatment — a flat `blue-50` background — on any variant, size, or inline fragment. It's the same treatment `DiffValue` and `TruncatedText` use for a revised value.

## Behavior

Text is presentational — it renders no interactive states of its own. Content wraps within its container by default; for line-clamped body copy with a Show more / Show less control, use `TruncatedText` instead.

## Usage Guidelines

### When to Use

Use the Text when:

* **Carto typography** – Headlines, body copy, and eyebrow labels need Carto type styles.
* **Section headings** – A heading needs a semantic level that is independent of its visual size.
* **Inline fragments** – A styled fragment sits on the same line as running copy or inside another Text.
* **Section labels** – A small, uppercased overline labels a section. Use the eyebrow variant.

### When not to use

Avoid using the Text for:

* **Line-clamped body copy** – Long body copy needs a Show more / Show less control. Use the [Truncated Text](https://anvil.servicetitan.com/docs/components/truncated-text/web.md) instead.
* **Block-level formatted content** – Content includes lists, tables, code, quotes, or multiple headings, which produce invalid markup inside Text. Use the [Markdown](https://anvil.servicetitan.com/docs/components/markdown/web.md) for formatted agent responses.

## Keyboard Interaction

Text renders no focusable elements of its own. When `text` composes an interactive child — a Carto `Link`, for example — that child's own keyboard interaction applies.

## Code

**Implementation**

ai-kit-text

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-text?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Text } from "@servicetitan/anvil2-ai-kit";

function App() {
  return <Text text="The quick brown fox jumps over the lazy dog." />;
}

export default App;
```

## Common Examples

To use the `Text`, import it from `@servicetitan/anvil2-ai-kit` and pass a required `text` prop. The kit forbids `children`. `text` must be HTML phrasing content: inline nodes only, not block elements.

```tsx theme={null}
import { Text } from "@servicetitan/anvil2-ai-kit";

function ExampleComponent() {
  return <Text text="Default body paragraph." />;
}
```

Prefer Carto components inside `text` when both a raw HTML element and a kit component exist: `Link` over `<a>`, kit icons over raw `<svg>`.

For truncation with Show more / Show less, use [`TruncatedText`](https://anvil.servicetitan.com/docs/components/truncated-text/design).

### Headline

Set `variant="headline"` and a required `el` (`"h1"`–`"h6"`) so the semantic level is independent of visual size. Headline `size` defaults to `"major"`.

ai-kit-text-headline-sizes

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-text-headline-sizes?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Text } from "@servicetitan/anvil2-ai-kit";

function App() {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
      <Text variant="headline" el="h2" size="hero" text="Headline — hero" />
      <Text variant="headline" el="h2" size="major" text="Headline — major" />
      <Text
        variant="headline"
        el="h2"
        size="substantial"
        text="Headline — substantial"
      />
      <Text
        variant="headline"
        el="h2"
        size="regular"
        text="Headline — regular"
      />
    </div>
  );
}

export default App;
```

### Body

Body is the default variant and renders a `<p>`. Size defaults to `"regular"`.

ai-kit-text-body-sizes

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-text-body-sizes?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Text } from "@servicetitan/anvil2-ai-kit";

function App() {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
      <Text size="featured" text="Body — featured: the quick brown fox" />
      <Text size="regular" text="Body — regular: the quick brown fox" />
      <Text size="compact" text="Body — compact: the quick brown fox" />
      <Text size="fine" text="Body — fine: the quick brown fox" />
    </div>
  );
}

export default App;
```

### Inline body

Set `inline` on body text to render a `<span>` instead of a `<p>` so fragments compose inside other text.

ai-kit-text-inline

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-text-inline?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Text } from "@servicetitan/anvil2-ai-kit";

function App() {
  return (
    <div>
      <Text inline text="Inline body fragment, " />
      <Text inline size="featured" text="featured-size inline, " />
      <Text inline size="compact" text="and a compact inline." />
    </div>
  );
}

export default App;
```

### Eyebrow

Eyebrow text always renders a `<span>` and does not accept `size`, `el`, or `inline`.

ai-kit-text-eyebrow

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-text-eyebrow?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Text } from "@servicetitan/anvil2-ai-kit";

function App() {
  return <Text variant="eyebrow" text="Section label" />;
}

export default App;
```

### Highlighted

Set `highlighted` to apply the suggested-change treatment on any variant.

ai-kit-text-highlighted

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/ai-kit-text-highlighted?file=src/App.tsx)

```tsx lines expandable theme={null}
import { Text } from "@servicetitan/anvil2-ai-kit";

function App() {
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
      <Text
        variant="headline"
        el="h2"
        size="major"
        highlighted
        text="Revised headline"
      />
      <Text highlighted text="Revised body copy" />
      <Text variant="eyebrow" highlighted text="Revised label" />
      <div>
        <Text inline text="Partial inline " />
        <Text inline highlighted text="highlight" />
      </div>
    </div>
  );
}

export default App;
```

## React Accessibility

* Choose `el` on headlines to match document structure, not visual size.
* Body `text` that includes interactive children such as `Link` must stay phrasing content so the wrapping `<p>` or `<span>` remains valid HTML.

**Text Props**

```tsx theme={null}
<Text variant="headline" el="h2" size="major" text="Page title" />
```

## `Text` Props

The `Text` accepts the following props. It is a discriminated union. `variant` selects the role; `el` is required on headlines; `inline` is body-only; eyebrow forbids `size`, `el`, and `inline`.

**text** `ReactNode` *required*

Text content. Must be HTML phrasing content. Block elements inside
`text` produce invalid HTML.

**className** `string`

Caller-supplied class merged onto the recipe class.

**el** `"h1" | "h2" | "h3" | "h4" | "h5" | "h6"`

Rendered heading tag. Required when `variant` is `"headline"`. Forbidden
on body and eyebrow.

**highlighted** `boolean` (default: false)

Applies the suggested-change highlight treatment on every variant.

**inline** `true`

Renders body text as a `<span>` instead of a `<p>`. Body only.

**size** `HeadlineSize | BodySize`

Visual scale. Headline sizes: `"regular"`, `"substantial"`, `"major"`
(default), `"hero"`. Body sizes: `"fine"`, `"compact"`, `"regular"`
(default), `"featured"`. Forbidden on eyebrow.

**variant** `"headline" | "body" | "eyebrow"` (default: body)

Type role. Defaults to `"body"` when omitted.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.