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

# Typography

export const LiveCode = ({children, customHeight, clickToLoad, example, fullWidth, fullHeight, hideCodeInLiveCode, screenshot, screenshotOnly, showCode: showCodeProp}) => {
  const SCREENSHOTS_BASE = "https://servicetitan.github.io/anvil2-docs-live-code/screenshots";
  const STACKBLITZ_BASE = "https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples";
  const [showCodeBlock, setShowCodeBlock] = useState(showCodeProp ?? false);
  const [isLocalOverride, setIsLocalOverride] = useState(false);
  useEffect(() => {
    const examplePath = `/images/live-code-screenshots-tmp/${example}.png`;
    fetch(examplePath, {
      method: "HEAD"
    }).then(r => {
      if (r.ok) setIsLocalOverride(true);
    }).catch(() => {});
  }, [example]);
  const screenshotBase = isLocalOverride ? "/images/live-code-screenshots-tmp" : SCREENSHOTS_BASE;
  if (screenshotOnly) {
    return <Frame className="flex flex-col">
        <div className="flex dark:hidden" style={{
      justifyContent: "center",
      alignItems: "center",
      width: fullWidth ? "100%" : "50%",
      minHeight: fullHeight ? "284px" : undefined,
      background: "#FFFFFF"
    }}>
          <img srcset={`${screenshotBase}/${example}.png, ${screenshotBase}/${example}-2x.png 2x`} src={`${screenshotBase}/${example}.png`} alt={example} noZoom />
        </div>
        <div className="hidden dark:flex" style={{
      justifyContent: "center",
      alignItems: "center",
      width: fullWidth ? "100%" : "50%",
      minHeight: fullHeight ? "284px" : undefined,
      background: "#141414"
    }}>
          <img srcset={`${screenshotBase}/${example}-dark.png, ${screenshotBase}/${example}-dark-2x.png 2x`} src={`${screenshotBase}/${example}-dark.png`} alt={example} noZoom />
        </div>
      </Frame>;
  }
  if (screenshot) {
    return <Frame className="flex flex-col -mb-2">
        <div className="flex dark:hidden bg-white dark:bg-codeblock border border-gray-950/10 dark:border-white/10 dark:twoslash-dark rounded-2xl overflow-hidden" style={{
      justifyContent: "center",
      alignItems: "center",
      width: fullWidth ? "100%" : "50%",
      minHeight: fullHeight ? "284px" : undefined
    }}>
          <img srcset={`${screenshotBase}/${example}.png, ${screenshotBase}/${example}-2x.png 2x`} src={`${screenshotBase}/${example}.png`} alt={example} noZoom />
        </div>

        <div className="hidden dark:flex bg-white dark:bg-codeblock border border-gray-950/10 dark:border-white/10 dark:twoslash-dark rounded-2xl overflow-hidden" style={{
      background: "#141414",
      justifyContent: "center",
      alignItems: "center",
      width: fullWidth ? "100%" : "50%",
      minHeight: fullHeight ? "284px" : undefined
    }}>
          <img srcset={`${screenshotBase}/${example}-dark.png, ${screenshotBase}/${example}-dark-2x.png 2x`} src={`${screenshotBase}/${example}-dark.png`} alt={example} noZoom />
        </div>

        <div className="flex justify-end items-center text-xs py-2 px-1 gap-4">
          {!showCodeProp ? <button className="inline-flex justify-end items-center text-gray-700 dark:text-gray-50 hover:text-blue-500 dark:hover:text-blue-300 transition-colors group self-end gap-1 cursor-pointer" onClick={() => setShowCodeBlock(!showCodeBlock)} style={{
      appearance: "none"
    }}>
              <Icon icon="code" size="12px" className="group-hover:bg-blue-500 dark:group-hover:bg-blue-300" />
              <span>{showCodeBlock ? "Hide code" : "Show code"}</span>
            </button> : null}

          <a className="inline-flex justify-end items-center hover:text-blue-500 dark:hover:text-blue-300 transition-colors group self-end gap-1" href={`${STACKBLITZ_BASE}/${example}?file=src/App.tsx`} target="_blank" rel="noreferrer">
            <Icon icon="bolt" size="12px" className="group-hover:bg-blue-500 dark:group-hover:bg-blue-300" />
            <span>StackBlitz demo</span>
          </a>
        </div>

        <div className="grid transition-[grid-template-rows] duration-300 ease-in-out overflow-auto overflow-y-hidden overflow-x-auto" style={showCodeBlock ? {
      gridTemplateRows: "1fr"
    } : {
      gridTemplateRows: "0fr"
    }}>
          <div style={{
      minHeight: 0,
      overflowX: "auto",
      overflowY: "hidden",
      marginBlockStart: "-1.25rem",
      marginBlockEnd: "-1.5rem"
    }}>
            {children}
          </div>
        </div>
      </Frame>;
  } else {
    return <div style={{
      display: "flex",
      width: fullWidth ? "100%" : "50%",
      minHeight: customHeight ? customHeight : "316px",
      resize: "vertical",
      overflow: "auto"
    }}>
        <iframe title={example} style={{
      flex: 1,
      width: fullWidth ? "100%" : "50%",
      minHeight: customHeight ? customHeight : "316px"
    }} src={`${STACKBLITZ_BASE}/${example}?embed=1&hideNavigation=1&hideExplorer=1&terminalHeight=0&file=src/App.tsx${clickToLoad ? "&ctl=1" : ""}${hideCodeInLiveCode ? "&view=preview" : ""}`} allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking" sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts" />
      </div>;
  }
};

Use typography to present content as clearly and efficiently as possible.

<Frame>
  <div className="w-full h-full bg-[#FFFFFF] p-2 rounded flex items-center justify-center">
    <img
      src="https://mintcdn.com/servicetitan/KE7wVYXA9MgEh_Ye/images/docs/web/foundations/shared/a-with-an-underline-as-an-icon-to-represent-typography.png?fit=max&auto=format&n=KE7wVYXA9MgEh_Ye&q=85&s=849232ee923837157a4fc9def25e4719"
      alt="&#x22;A&#x22; with an underline as an icon to represent
typography"
      width="96"
      height="96"
      data-path="images/docs/web/foundations/shared/a-with-an-underline-as-an-icon-to-represent-typography.png"
    />
  </div>
</Frame>

## Overview

Too many type sizes and styles at once can spoil any layout. A limited set of type variations are supported that work well with each other.

### Usage Guide

##### Legend

✅ recommended

⚠️ use with caution

❌ do not use

#### Headline Text

|                    | xlarge | large | medium | small |
| ------------------ | ------ | ----- | ------ | ----- |
| On-boarding Wizard | ✅      | ⚠️    | ⚠️     | ❌     |
| Page Title         | ⚠️     | ✅     | ⚠️     | ❌     |
| Section Title      | ❌      | ❌     | ✅      | ✅     |
| Dialog Title       | ❌      | ❌     | ✅      | ❌     |
| Drawer Title       | ❌      | ✅     | ✅      | ✅     |
| Popover Title      | ❌      | ❌     | ❌      | ✅     |

#### Body Text

|                      | xlarge | large | medium | small |
| -------------------- | ------ | ----- | ------ | ----- |
| Paragraph            | ⚠️     | ✅     | ⚠️     | ❌     |
| Table Cell           | ⚠️     | ⚠️    | ⚠️     | ✅     |
| Single Piece of Data | ❌      | ✅     | ⚠️     | ⚠️    |
| Helper Text          | ❌      | ⚠️    | ✅      | ✅     |
| Meta Data            | ❌      | ⚠️    | ⚠️     | ✅     |

### Pairing

Our Typography uses semantic naming to pair sizes which helps with the consistency in overall application as well as the visual hierarchy and space management.

This pairing method is ideal for text components that are directly or semi-directly related or grouped together in a card or section.

##### Pairing Examples

<LiveCode example="typography-pairing-size-medium" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Text, Flex } from "@servicetitan/anvil2";

  function App() {
    return (
      <Flex direction="column">
        <Text variant="headline" el="h4">
          Headline Default
        </Text>
        <br />
        <Text variant="eyebrow">Eyebrow Default</Text>
        <Text variant="body">This is default BodyText component</Text>
      </Flex>
    );
  }
  export default App;
  ```
</LiveCode>

<LiveCode example="typography-pairing-size-large" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Text, Flex } from "@servicetitan/anvil2";

  function App() {
    return (
      <Flex direction="column">
        <Text size="large" variant="headline" el="h4">
          Headline Large
        </Text>
        <br />
        <Text size="large" variant="eyebrow">
          Eyebrow Large
        </Text>
        <Text size="large" variant="body">
          This is large BodyText component
        </Text>
      </Flex>
    );
  }
  export default App;
  ```
</LiveCode>

Use same size for sibling items.

<LiveCode example="typography-pairing-size-sibling" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Text, Flex, Divider, TextField } from "@servicetitan/anvil2";

  function App() {
    return (
      <Flex direction="column">
        <Text size="small" variant="headline" el="h4">
          Headline Large
        </Text>
        <Text size="small" variant="body">
          This is large BodyText component
        </Text>
        <Divider spacing="2" />
        <Text size="small" variant="headline" el="h4">
          Headline Large
        </Text>
        <br />
        <Text size="small" variant="eyebrow">
          Eyebrow Large
        </Text>
        <Text size="small" variant="body">
          This is large BodyText component
        </Text>
        <br />
        <TextField size="small" label="First Name" />
      </Flex>
    );
  }
  export default App;
  ```
</LiveCode>

### Deviation

In some cases where you need higher contrast between headline and body, headline can size up one or body can size down one. Do not deviate up with body text, the body text and headline size would be the same creating ineffective typographical hierarchy.

##### Deviation Examples

<LiveCode example="typography-deviation" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Text, Flex, Divider } from "@servicetitan/anvil2";

  function App() {
    return (
      <Flex direction="column" gap="3">
        <Flex direction="column">
          <Text variant="headline" size="xlarge" el="h4">
            Headline xLarge
          </Text>
          <Text variant="eyebrow" size="large">
            Body Large
          </Text>
        </Flex>
        <Divider />
        <Flex direction="column">
          <Text variant="headline" el="h4">
            Headline Default
          </Text>
          <Text variant="eyebrow" size="small">
            Body Small
          </Text>
        </Flex>
        <Divider />
        <Flex direction="column">
          <Text variant="headline" size="small" el="h4">
            Headline Large
          </Text>
          <Text variant="eyebrow" size="large">
            Body Large
          </Text>
        </Flex>
      </Flex>
    );
  }
  export default App;
  ```
</LiveCode>

## Variations

### Headline

Font Family: `Sofia Pro`

Weight: `Bold`

<LiveCode example="typography-variations-headline" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Text, Flex } from "@servicetitan/anvil2";

  function App() {
    return (
      <Flex direction="column" gap="3">
        <Text el="h4" variant="headline" size="xlarge">
          X-large, 2rem (32px @ 16px base)
        </Text>
        <Text el="h4" variant="headline" size="large">
          Large, 1.5rem (24px @ 16px base)
        </Text>
        <Text el="h4" variant="headline">
          Medium(default), 1.25rem (20px @ 16px base)
        </Text>
        <Text el="h4" variant="headline" size="small">
          Small, 1rem (16px @ 16px base)
        </Text>
      </Flex>
    );
  }
  export default App;
  ```
</LiveCode>

### Body

Font Family: `Nunito Sans`

Weight: `Regular, Bold`

<LiveCode example="typography-variations-bodytext" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Text, Flex } from "@servicetitan/anvil2";

  function App() {
    return (
      <Flex direction="column" gap="3">
        <Text size="xlarge">X-large, 1.5rem (24px @ 16px base)</Text>
        <Text size="large">Large, 1.25rem (20px @ 16px base)</Text>
        <Text>Medium(default), 1rem (16px @ 16px base)</Text>
        <Text size="small">Small, .875rem (14px @ 16px base)</Text>
      </Flex>
    );
  }
  export default App;
  ```
</LiveCode>

### Eyebrow

Font Family: `Nunito Sans`

Weight: `Semibold`

Case: `Uppercase`

Style: `Subdued`

<LiveCode example="typography-variations-eyebrow" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Text, Flex } from "@servicetitan/anvil2";

  function App() {
    return (
      <Flex direction="column" gap="3">
        <Text variant="eyebrow" size="large">
          Large, 1rem (16px @ 16px base)
        </Text>
        <Text variant="eyebrow">Medium(default), .875rem (14px @ 16px base)</Text>
        <Text variant="eyebrow" size="small">
          Small, .625rem (10px @ 16px base)
        </Text>
      </Flex>
    );
  }
  export default App;
  ```
</LiveCode>

## Style

### Subdued

You can deemphasize text by making it a lighter shade of grey.

<LiveCode example="typography-style-subdued" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Text } from "@servicetitan/anvil2";

  function App() {
    return (
      <Text>
        In a paragraph of text, when you have words that need to be deemphasized,{" "}
        <Text inline subdued>
          subdued text
        </Text>{" "}
        becomes less apparent
      </Text>
    );
  }
  export default App;
  ```
</LiveCode>

A subdued line of copy can be used for disclaimers or helpful notes below form fields.

<LiveCode example="typography-style-description" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Text } from "@servicetitan/anvil2";

  function App() {
    return (
      <Text subdued>You can only upload photos in jpg, png, and tif formats</Text>
    );
  }
  export default App;
  ```
</LiveCode>

#### When not to use

<LiveCode example="typography-style-contrast-dont" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Text } from "@servicetitan/anvil2";

  function App() {
    return (
      <div
        style={{
          padding: "var(--size-2)",
          backgroundColor: "var(--background-color-strongest)",
        }}
      >
        <Text subdued>My contrast is 3.27:1, below AA level requirement</Text>
      </div>
    );
  }
  export default App;
  ```
</LiveCode>

<Danger>**Don't**</Danger>

Do not use subdued style on top of **background-color-strongest** as it does not meet the contrast requirement for AA level.

### Italic

You can emphasize text by italicizing it.

<LiveCode example="typography-italic" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Text } from "@servicetitan/anvil2";

  function App() {
    return (
      <Text>
        In a paragraph of text, when you have words that need to be emphasized,{" "}
        <i>italic text</i> can be used
      </Text>
    );
  }
  export default App;
  ```
</LiveCode>

#### Bold

You can emphasize text by bolding it.

<LiveCode example="typography-bold" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Text } from "@servicetitan/anvil2";

  function App() {
    return (
      <Text>
        In a paragraph of text, when you have words that need to be emphasized,{" "}
        <b>bold text</b> can be used
      </Text>
    );
  }
  export default App;
  ```
</LiveCode>
