> ## 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

> The text component enables designers and developers to use properly styled typography.

> [!NOTE]
>
> For development, import `Text` from
> `@servicetitan/anvil2`. For design, find it in the
> [Anvil2 file](https://www.figma.com/design/xaNQsvRKczoxu7pj0M6QT8/Anvil2-v3?node-id=55-8508).

![](https://mintcdn.com/servicetitan/H5FwKyiqhPVZ1UJQ/images/docs/web/components/shared/text-overview.png?fit=max\&auto=format\&n=H5FwKyiqhPVZ1UJQ\&q=85\&s=2cd54400ec5f4b325d0370c987b99c11)

## Options

Text supports body text, headline, and eyebrow configurations with multiple sizing options to accommodate various typography scenarios.

### Body Text

text-body-playground

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

```tsx lines theme={null}
import { Text, Grid } from "@servicetitan/anvil2";

function App() {
  return (
    <Grid
      alignContent="center"
      style={{
        height: "80px",
      }}
    >
      <Text size="xlarge">Body Text</Text>
    </Grid>
  );
}

export default App;
```

#### Body Text sizing

text-body

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

```tsx lines theme={null}
import { Text, Flex } from "@servicetitan/anvil2";

function App() {
  return (
    <Flex direction="column">
      <Text size="small" variant="body">
        Small body text
      </Text>
      <Text size="medium" variant="body">
        Medium body text
      </Text>
      <Text size="large" variant="body">
        Large body text
      </Text>
      <Text size="xlarge" variant="body">
        X-Large body text
      </Text>
    </Flex>
  );
}

export default App;
```

| Value | Size |
| - | - |
| Small | 0.875rem / 14px |
| Medium (Default) | 1rem / 16px |
| Large | 1.25rem / 20px |
| Extra Large | 1.5rem / 24px |

#### Styling

text-body-style

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

```tsx lines theme={null}
import { Text, Grid } from "@servicetitan/anvil2";

function App() {
  return (
    <Grid gap="6">
      <Text variant="body" size="medium">
        Body text with a <strong>bold styling</strong> applied to it.
      </Text>
      <Text variant="body" size="medium">
        Body text with a <i>italic styling</i> applied to it.
      </Text>
      <Text variant="body" size="medium">
        Body text with a{" "}
        <Text inline subdued>
          subdued styling
        </Text>{" "}
        applied to it.
      </Text>
    </Grid>
  );
}

export default App;
```

### Headline

text-headline-playground

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

```tsx lines theme={null}
import { Text, Grid } from "@servicetitan/anvil2";

function App() {
  return (
    <Grid
      alignContent="center"
      style={{
        height: "80px",
      }}
    >
      <Text variant="headline" size="xlarge" el="h1">
        Headline
      </Text>
    </Grid>
  );
}

export default App;
```

#### Headline sizing

text-headline

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

```tsx lines theme={null}
import { Text, Flex } from "@servicetitan/anvil2";

function App() {
  return (
    <Flex direction="column">
      <Text el="h4" size="small" variant="headline">
        H4 Headline
      </Text>
      <Text el="h3" size="medium" variant="headline">
        H3 Headline
      </Text>
      <Text el="h2" size="large" variant="headline">
        H2 Headline
      </Text>
      <Text el="h1" size="xlarge" variant="headline">
        H1 Headline
      </Text>
    </Flex>
  );
}

export default App;
```

| Value | Size |
| - | - |
| Small | 1rem / 16px |
| Medium (Default) | 1.25rem / 20px |
| Large | 1.5rem / 24px |
| Extra Large | 2rem / 32px |

### Eyebrow

text-eyebrow-playground

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

```tsx lines theme={null}
import { Text, Grid } from "@servicetitan/anvil2";

function App() {
  return (
    <Grid
      alignContent="center"
      style={{
        height: "80px",
      }}
    >
      <Text variant="eyebrow" size="large">
        Eyebrow
      </Text>
    </Grid>
  );
}

export default App;
```

#### Eyebrow sizing

text-eyebrow

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

```tsx lines theme={null}
import { Text, Flex } from "@servicetitan/anvil2";

function App() {
  return (
    <Flex direction="column">
      <Text size="small" variant="eyebrow">
        Eyebrow text
      </Text>
      <Text size="medium" variant="eyebrow">
        Eyebrow text
      </Text>
      <Text size="large" variant="eyebrow">
        Eyebrow text
      </Text>
    </Flex>
  );
}

export default App;
```

| Value | Size |
| - | - |
| Small | 0.625rem / 10px |
| Medium (Default) | 0.75rem / 12px |
| Large | 1rem / 16px |

## Behavior

Text responds to different style and size requirements while maintaining consistent typography.

## Usage Guidelines

| Standard | Requirement |
| - | - |
| DoConvey text throughout a page | The text component should be regularly used to convey text throughout a page. Each of the major text styles used in the design system are options within Text. |
| DoFollow typography foundations | Refer to the [typography foundations](https://anvil.servicetitan.com/docs/foundations/typography.md) for suggested type pairing and size configurations. |
| DoApply heading levels to headline text | The headline variant of Text should apply an appropriate HTML section heading (e.g., `h1`, `h2`). This value is independent of the size option applied to headlines. Inside a Page, PageHeader already renders the `h1`, so body headlines start at `h2`. |
| DoLeave size off section headings | Omit `size` on section titles so they read as titles (default). Reserve `size="small"` for the deepest sub-labels. |
| Don'tUse in most components | Text is not directly used in most components. In those cases, the built-in type opinions of the component are used instead. |

## Content

Content within Text should follow typography best practices for readability and hierarchy.

### Accessibility

Out of the box, text provides necessary accessibility around sizing and color contrast.

#### Text color contrast with backgrounds

Text should follow the [WCAG AA guidance on color contrast](https://www.w3.org/TR/WCAG22/#contrast-minimum). By default, Anvil's Text will provide at least 4.5:1 contrast with a white background.

Use caution when using subdued on other background values, or when using custom color values in general, as they may not meet contrast guidance.

For more guidance on text hierarchy and semantic markup, see [semantic markup best practices](https://anvil.servicetitan.com/docs/accessibility/semantic-markup.md).

## Code

**Implementation**

text-playground

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

```tsx lines expandable theme={null}
import { Text, Flex } from "@servicetitan/anvil2";

function App() {
  return (
    <Flex direction="column">
      <Text variant="headline" el="h2" size="large">
        Headline
      </Text>
      <Text variant="eyebrow" size="large">
        Eyebrow
      </Text>
      <Text variant="body">Body text. Lorem ipsum dolor sit amet.</Text>
    </Flex>
  );
}

export default App;
```

## Common Examples

```tsx theme={null}
import { Flex, Text } from "@servicetitan/anvil2";

function ExampleComponent() {
  return (
    <Flex direction="column">
      <Text variant="headline" el="h2">
        Headline text
      </Text>
      <Text variant="eyebrow" size="large">
        Eyebrow
      </Text>
      <Text>Regular body text.</Text>
    </Flex>
  );
}
```

### Text variants

The `Text` component accepts one of three options for the `variant` prop:

* `"body"` (default): renders as HTML `p` or `span` element, if `inline` is set to `true`
* `"eyebrow"`: renders as HTML `span` element
* `"headline"`: renders as HTML heading element (`h1` through `h4`) element, based on `el` prop

#### Body

text-body

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

```tsx lines expandable theme={null}
import { Text, Flex } from "@servicetitan/anvil2";

function App() {
  return (
    <Flex direction="column">
      <Text size="small" variant="body">
        Small body text
      </Text>
      <Text size="medium" variant="body">
        Medium body text
      </Text>
      <Text size="large" variant="body">
        Large body text
      </Text>
      <Text size="xlarge" variant="body">
        X-Large body text
      </Text>
    </Flex>
  );
}

export default App;
```

#### Eyebrow

text-eyebrow

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

```tsx lines expandable theme={null}
import { Text, Flex } from "@servicetitan/anvil2";

function App() {
  return (
    <Flex direction="column">
      <Text size="small" variant="eyebrow">
        Eyebrow text
      </Text>
      <Text size="medium" variant="eyebrow">
        Eyebrow text
      </Text>
      <Text size="large" variant="eyebrow">
        Eyebrow text
      </Text>
    </Flex>
  );
}

export default App;
```

#### Headline

text-headline

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

```tsx lines expandable theme={null}
import { Text, Flex } from "@servicetitan/anvil2";

function App() {
  return (
    <Flex direction="column">
      <Text el="h4" size="small" variant="headline">
        H4 Headline
      </Text>
      <Text el="h3" size="medium" variant="headline">
        H3 Headline
      </Text>
      <Text el="h2" size="large" variant="headline">
        H2 Headline
      </Text>
      <Text el="h1" size="xlarge" variant="headline">
        H1 Headline
      </Text>
    </Flex>
  );
}

export default App;
```

### Headlines without a bottom margin

Headlines carry a bottom margin so they space correctly above the content that follows. When a headline is aligned against a sibling element instead, that trailing margin shifts it off center. Set `noMargin` to drop it:

text-no-margin

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

```tsx lines expandable theme={null}
import { Text, Chip, Flex } from "@servicetitan/anvil2";

function App() {
  return (
    <Flex alignItems="center" gap="2">
      <Text variant="headline" el="h2" size="large" noMargin>
        Invoices
      </Text>
      <Chip label="Draft" />
    </Flex>
  );
}

export default App;
```

### Nesting body text

When using body text within body text, make sure to use the `inline` prop on any of the child `Body` components to render a `span` instead of `p`.

text-inline

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

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

function App() {
  return (
    <Text size="medium" variant="body">
      The outer text is in a <code>p</code> element, but the{" "}
      <Text variant="body" inline style={{ fontWeight: 700 }}>
        inner text
      </Text>{" "}
      is in a <code>span</code> element.
    </Text>
  );
}

export default App;
```

### Subdued body text

If `subdued` is set to `true` on a body text, it will use a de-emphasized color:

text-subdued

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

```tsx lines expandable theme={null}
import { Text, Flex } from "@servicetitan/anvil2";

function App() {
  return (
    <Flex gap="6">
      <Text variant="body">Regular</Text>
      <Text variant="body" subdued>
        Subdued
      </Text>
    </Flex>
  );
}

export default App;
```

### The useAccessibleColor hook

The Anvil2 `useAccessibleColor` hook makes it easy to determine which text color to use given a specific background color without making it inaccessible. This hook accepts two parameters, and returns an object with both `foreground` and `background` colors. In the case that no color can be made accessible with the given color, the `background` color will be adjusted until it can.

```tsx theme={null}
// accepts any valid css color format and hex with no #
const { foreground, background } = useAccessibleColor("0066CC");
```

text-useaccessiblecolor

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

```tsx lines expandable theme={null}
import { Text, Flex, Card, useAccessibleColor } from "@servicetitan/anvil2";

function App() {
  const { foreground: fg1, background: bg1 } = useAccessibleColor("#0066CC");

  const { foreground: fg2, background: bg2 } =
    useAccessibleColor("hsl(339,100,94)");

  return (
    <Flex gap="2">
      <Card style={{ backgroundColor: bg1 }}>
        <Text style={{ color: fg1 }} inline>
          This is accessible 🎉
        </Text>
      </Card>
      <Card style={{ backgroundColor: bg2 }}>
        <Text style={{ color: fg2 }} inline>
          This is accessible 🎉
        </Text>
      </Card>
    </Flex>
  );
}

export default App;
```

**Note:** Anvil2 components and tokens already account for accessible colors internally, so this hook should only be needed when working with custom colors.

**Text Props**

```tsx theme={null}
<Text variant="body" size="medium" inline={false} subdued={false} el="h2">
  Text content
</Text>
```

## `Text` Props

Depending on the variant, the `Text` component can accept any valid HTML `header`, `p`, or `span` props, in addition to the ones listed below. See the [Text variants section](https://anvil.servicetitan.com/docs/components/text/react-native.md#text-variants) for specifics.

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

Only valid when `variant="headline"`. Required when using headline variant.

**aiMark** `boolean | AiMarkWithTooltipOrPopoverConfig`

Only valid when `variant="headline"`. When set, renders the AI mark inline after the headline text. Use `true` for the sparkle only, or pass tooltip or popover configuration. See [AI Mark](https://anvil.servicetitan.com/docs/components/ai-mark/code).

**inline** `boolean`

Only valid when `variant="body"`.

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

Only valid when `variant="headline"`. Removes the headline's bottom margin so its layout box hugs the text. Use it when a headline sits alongside a sibling element, such as a `Chip`, where the trailing margin would offset the alignment. The `body` and `eyebrow` variants have no margins, so they do not need it.

**size** `"small" | "medium" | "large" | "xlarge"` (default: medium)

Note: `"xlarge"` is not available for `variant="eyebrow"`.

**subdued** `boolean`

Only valid when `variant="body"`.

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


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