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

# Illustrations

> The Anvil kit for providing illustrations to use in UI.

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>;
  }
};

The Illustrations kit is the published SVG library for Anvil2 empty states, onboarding, and outcome screens. Import files from `@servicetitan/anvil2-illustrations`. There is no dedicated Illustration component.

Illustrations tell a small visual story. Use [icons](/docs/web/icons) for compact glyphs inside controls.

## Installation

```bash theme={null}
npm install @servicetitan/anvil2-illustrations
```

## Import

With SVGR configured, the default import is a React component:

```tsx theme={null}
import NoResults from "@servicetitan/anvil2-illustrations/illustrations/empty-state-no-search-results-light.svg";

<NoResults aria-hidden="true" height={200} />;
```

Without SVGR, pass the file to `img`:

```tsx theme={null}
import NoResults from "@servicetitan/anvil2-illustrations/illustrations/empty-state-no-search-results-light.svg";

<img src={NoResults} alt="" width={240} height={180} />;
```

## In context

Compose the SVG with Anvil2 layout primitives. Set one dimension and let the other scale from the 453:380 viewBox. Empty-state examples use `height={200}`.

<LiveCode example="illustrations-kit-empty-search" screenshot fullWidth>
  ```tsx lines theme={null}
  import {
    AnvilProvider,
    Button,
    Card,
    Flex,
    Text,
    usePrefersColorScheme,
  } from "@servicetitan/anvil2";
  import NoSearchResultsLight from "@servicetitan/anvil2-illustrations/illustrations/empty-state-no-search-results-light.svg";
  import NoSearchResultsDark from "@servicetitan/anvil2-illustrations/illustrations/empty-state-no-search-results-dark.svg";

  function App() {
    const { mode } = usePrefersColorScheme();

    const NoSearchResults =
      mode === "dark" ? NoSearchResultsDark : NoSearchResultsLight;

    return (
      <AnvilProvider themeData={{ mode }}>
        <Card padding="large">
          <Flex direction="column" alignItems="center" gap={4}>
            <NoSearchResults aria-hidden="true" height={200} />
            <Text variant="headline" el="h2">
              No matching jobs
            </Text>
            <Text subdued style={{ textAlign: "center" }}>
              Try a different name or clear filters to see all jobs.
            </Text>
            <Button appearance="secondary">Clear Filters</Button>
          </Flex>
        </Card>
      </AnvilProvider>
    );
  }

  export default App;
  ```
</LiveCode>

## Accessibility

* When title and body already explain the state, treat the illustration as decorative (`aria-hidden` or empty `alt`).
* When the illustration alone conveys meaning, provide `alt` that describes the outcome, not the drawing style.

## Design guidance

<Columns cols={2}>
  <Card title="Foundations" icon="palette" href="/docs/kits/illustrations/foundations">
    Illustration language: style, color, form, perspective, line work, texture, and character.
  </Card>

  <Card title="Empty states" icon="image" href="/docs/kits/illustrations/empty-states">
    Trade personalization, scenario guidance, and sample copy.
  </Card>

  <Card title="Figma library" icon="figma" href="https://www.figma.com/design/9AdQ0X9Wgx54HHFPM1xkOT/%E2%9C%A8NEW%E2%9C%A8-Illustration-Library?m=auto&node-id=2120-2">
    Design source for illustration language and empty-state usage.
  </Card>

  <Card title="Package source" icon="github" href="https://github.com/servicetitan/hammer/tree/main/packages/anvil2-illustrations">
    SVG files in `@servicetitan/anvil2-illustrations`.
  </Card>
</Columns>

***

## Connect with us

<Columns cols={2}>
  <Card title="Get help on Slack" icon="slack" href="https://servicetitan.enterprise.slack.com/archives/CBSRGHTRS">
    You can reach the Anvil team in the #ask-designsystem Slack channel.
  </Card>

  <Card title="Schedule office hours" icon="calendar" href="https://servicetitan.enterprise.slack.com/archives/CBSRGHTRS">
    Join the Anvil team for office hours on Mondays or Wednesdays to get hands-on help.
  </Card>

  <Card title="Report an issue" icon="jira" href="https://servicetitan.atlassian.net/secure/CreateIssue.jspa?issuetype=1&pid=11329">
    Ran into a bug in the code or design? We use Jira to track outstanding
    issues with Anvil.
  </Card>

  <Card title="Suggest an idea" icon="lightbulb" href="https://slack.com/shortcuts/Ft07EXNJSPS7/f598de9eda7177f477aaddbbc5701e15">
    Have an idea for a component, pattern, or documentation? Fill out the Feature Request Form in Slack.
  </Card>

  <Card title="View roadmap" icon="map" href="/docs/resources/roadmap">
    View what is coming up this year for the design system.
  </Card>

  <Card title="Contribute to Anvil2" icon="handshake" href="https://servicetitan.atlassian.net/wiki/spaces/ADS/pages/2054129026/Designer+Contribution+to+Anvil">
    Interested in contributing to Anvil? Read our contribution guide to learn
    more!
  </Card>
</Columns>
