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

# Empty states

> Example scenarios, guidance, and sample copy.

> **[Github mappings](https://servicetitan.atlassian.net/wiki/spaces/ADS/pages/4694638713/Utilities+Empty+State+Illustration+Mapping)**

## First Use Empty State

Use a first-use illustration when the user opens a feature for the first time and there is no data yet because no action has been taken.

illustrations-kit-trade-first-use

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

```tsx lines theme={null}
import type { ComponentType, SVGProps } from "react";
import {
  AnvilProvider,
  Chip,
  Flex,
  Text,
  usePrefersColorScheme,
} from "@servicetitan/anvil2";
import {
  EmptyStateCommercialEmergencyComplianceFirstUse,
  EmptyStateCommercialExteriorsFirstUse,
  EmptyStateCommercialInteriorsFirstUse,
  EmptyStateCommercialMechanicalFirstUse,
  EmptyStateCommercialPropertyCareFirstUse,
  EmptyStateResidentialEmergencyComplianceFirstUse,
  EmptyStateResidentialExteriorsFirstUse,
  EmptyStateResidentialInteriorsFirstUse,
  EmptyStateResidentialMechanicalFirstUse,
  EmptyStateResidentialPropertyCareFirstUse,
} from "@servicetitan/anvil2-illustrations";

// Matches the Chip fills from Figma; Chip derives the border and text
// colors from this background automatically via useAccessibleColor.
const RESIDENTIAL_CHIP_COLOR = "#e0f2ff";
const COMMERCIAL_CHIP_COLOR = "#f1edff";

type Trade = {
  label: string;
  Illustration: ComponentType<SVGProps<SVGSVGElement>>;
};

const RESIDENTIAL_TRADES: Trade[] = [
  {
    label: "Property Care",
    Illustration: EmptyStateResidentialPropertyCareFirstUse,
  },
  { label: "Exteriors", Illustration: EmptyStateResidentialExteriorsFirstUse },
  {
    label: "Mechanical",
    Illustration: EmptyStateResidentialMechanicalFirstUse,
  },
  {
    label: "Emergency & Compliance",
    Illustration: EmptyStateResidentialEmergencyComplianceFirstUse,
  },
  { label: "Interiors", Illustration: EmptyStateResidentialInteriorsFirstUse },
];

const COMMERCIAL_TRADES: Trade[] = [
  {
    label: "Property Care",
    Illustration: EmptyStateCommercialPropertyCareFirstUse,
  },
  { label: "Exteriors", Illustration: EmptyStateCommercialExteriorsFirstUse },
  { label: "Mechanical", Illustration: EmptyStateCommercialMechanicalFirstUse },
  {
    label: "Emergency & Compliance",
    Illustration: EmptyStateCommercialEmergencyComplianceFirstUse,
  },
  { label: "Interiors", Illustration: EmptyStateCommercialInteriorsFirstUse },
];

function TradeRow({
  chipLabel,
  chipColor,
  trades,
}: {
  chipLabel: string;
  chipColor: string;
  trades: Trade[];
}) {
  return (
    <Flex direction="column" gap={3} style={{ width: "fit-content" }}>
      <Chip label={chipLabel} size="small" color={chipColor} />
      <Flex gap={3} alignItems="flex-start">
        {trades.map(({ label, Illustration }) => (
          <Flex key={label} direction="column" alignItems="center" gap={2}>
            <div
              style={{
                height: 116,
                width: 170,
                display: "flex",
                alignItems: "flex-end",
                justifyContent: "center",
              }}
            >
              <Illustration
                aria-hidden="true"
                style={{
                  maxWidth: 170,
                  maxHeight: 116,
                  width: "auto",
                  height: "auto",
                }}
              />
            </div>
            <Text
              subdued
              style={{
                fontSize: 10,
                textTransform: "uppercase",
                letterSpacing: "0.02em",
              }}
            >
              {label}
            </Text>
          </Flex>
        ))}
      </Flex>
    </Flex>
  );
}

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

  return (
    <AnvilProvider themeData={{ mode }}>
      <Flex direction="column" gap={6}>
        <TradeRow
          chipLabel="Residential"
          chipColor={RESIDENTIAL_CHIP_COLOR}
          trades={RESIDENTIAL_TRADES}
        />
        <TradeRow
          chipLabel="Commercial"
          chipColor={COMMERCIAL_CHIP_COLOR}
          trades={COMMERCIAL_TRADES}
        />
      </Flex>
    </AnvilProvider>
  );
}

export default App;
```

### Usage Guidance

**When to Use:** These illustrations are ideal for screens or workflows where the user is encountering a feature or tool for the first time, and no data is yet available because no actions have been taken.

**Example scenarios**

* A newly onboarded user views their job scheduling screen for the first time.
* A user opens a reporting dashboard that hasn't been configured or populated.

**Sample copy**

* **Header:** "Ready to hit the road?"
* **Body:** "Your shop is ready for action! Start by scheduling a job or adding your first task to see things come alive."

> [!TIP]
>
> Pair the illustration with a clear call-to-action such as "Add a Job" or
> "Create a Report".

## User Cleared Empty State

Display a user-cleared illustration when the user has completed a task or cleared every item from a workflow, so there is nothing left to show.

illustrations-kit-trade-user-cleared

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

```tsx lines theme={null}
import type { ComponentType, SVGProps } from "react";
import {
  AnvilProvider,
  Chip,
  Flex,
  Text,
  usePrefersColorScheme,
} from "@servicetitan/anvil2";
import {
  EmptyStateCommercialEmergencyComplianceUserCleared,
  EmptyStateCommercialExteriorsUserCleared,
  EmptyStateCommercialInteriorsUserCleared,
  EmptyStateCommercialMechanicalUserCleared,
  EmptyStateCommercialPropertyCareUserCleared,
  EmptyStateResidentialEvergreenUserCleared,
} from "@servicetitan/anvil2-illustrations";

// Matches the Chip fills from Figma; Chip derives the border and text
// colors from this background automatically via useAccessibleColor.
const RESIDENTIAL_CHIP_COLOR = "#e0f2ff";
const COMMERCIAL_CHIP_COLOR = "#f1edff";

type Trade = {
  label: string;
  Illustration: ComponentType<SVGProps<SVGSVGElement>>;
};

const COMMERCIAL_TRADES: Trade[] = [
  {
    label: "Property Care",
    Illustration: EmptyStateCommercialPropertyCareUserCleared,
  },
  {
    label: "Exteriors",
    Illustration: EmptyStateCommercialExteriorsUserCleared,
  },
  {
    label: "Mechanical",
    Illustration: EmptyStateCommercialMechanicalUserCleared,
  },
  {
    label: "Emergency & Compliance",
    Illustration: EmptyStateCommercialEmergencyComplianceUserCleared,
  },
  {
    label: "Interiors",
    Illustration: EmptyStateCommercialInteriorsUserCleared,
  },
];

function IllustrationBox({
  Illustration,
}: {
  Illustration: ComponentType<SVGProps<SVGSVGElement>>;
}) {
  return (
    <div
      style={{
        height: 116,
        width: 170,
        display: "flex",
        alignItems: "flex-end",
        justifyContent: "center",
      }}
    >
      <Illustration
        aria-hidden="true"
        style={{ maxWidth: 170, maxHeight: 116, width: "auto", height: "auto" }}
      />
    </div>
  );
}

function TradeLabel({ children }: { children: string }) {
  return (
    <Text
      subdued
      style={{
        fontSize: 10,
        textTransform: "uppercase",
        letterSpacing: "0.02em",
        textAlign: "center",
      }}
    >
      {children}
    </Text>
  );
}

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

  return (
    <AnvilProvider themeData={{ mode }}>
      <Flex direction="column" gap={6}>
        <Flex direction="column" gap={3} style={{ width: "fit-content" }}>
          <Chip
            label="Residential"
            size="small"
            color={RESIDENTIAL_CHIP_COLOR}
          />
          <Flex direction="column" alignItems="center" gap={2}>
            <IllustrationBox
              Illustration={EmptyStateResidentialEvergreenUserCleared}
            />
            <TradeLabel>
              Property Care, Exteriors, Mechanical, Emergency & Compliance,
              Interiors
            </TradeLabel>
          </Flex>
        </Flex>
        <Flex direction="column" gap={3} style={{ width: "fit-content" }}>
          <Chip label="Commercial" size="small" color={COMMERCIAL_CHIP_COLOR} />
          <Flex gap={3} alignItems="flex-start">
            {COMMERCIAL_TRADES.map(({ label, Illustration }) => (
              <Flex key={label} direction="column" alignItems="center" gap={2}>
                <IllustrationBox Illustration={Illustration} />
                <TradeLabel>{label}</TradeLabel>
              </Flex>
            ))}
          </Flex>
        </Flex>
      </Flex>
    </AnvilProvider>
  );
}

export default App;
```

### Usage Guidance

**When to Use:** These illustrations are ideal for screens or workflows where the user has completed a task or cleared every item from a workflow, so there is nothing left to show.

**Example scenarios**

* An inbox for customer inquiries has been cleared
* A technician's checklist for the day is complete

**Sample copy**

* **Header:** "Nothing left on your plate!"
* **Body:** "You're all caught up. Time to enjoy a well-deserved coffee break."

> [!TIP]
>
> Use this illustration and copy as a light acknowledgment of the user's
> progress so the empty screen feels rewarding.

## Success State

Display a success illustration when the user completes a workflow or hits a significant milestone, especially after a complex or time-intensive task.

illustrations-kit-trade-success

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

```tsx lines theme={null}
import type { ComponentType, ReactNode, SVGProps } from "react";
import {
  AnvilProvider,
  Chip,
  Flex,
  Text,
  usePrefersColorScheme,
} from "@servicetitan/anvil2";
import {
  EmptyStateCommercialEvergreenSuccess,
  EmptyStateResidentialEvergreenSuccess,
} from "@servicetitan/anvil2-illustrations";

// Matches the Chip fills from Figma; Chip derives the border and text
// colors from this background automatically via useAccessibleColor.
const RESIDENTIAL_CHIP_COLOR = "#e0f2ff";
const COMMERCIAL_CHIP_COLOR = "#f1edff";

const TRADES_LABEL =
  "Property Care, Exteriors, Mechanical, Emergency & Compliance, Interiors";

function IllustrationBox({
  Illustration,
}: {
  Illustration: ComponentType<SVGProps<SVGSVGElement>>;
}) {
  return (
    <div
      style={{
        height: 116,
        width: 170,
        display: "flex",
        alignItems: "flex-end",
        justifyContent: "center",
      }}
    >
      <Illustration
        aria-hidden="true"
        style={{ maxWidth: 170, maxHeight: 116, width: "auto", height: "auto" }}
      />
    </div>
  );
}

function TradeLabel({ children }: { children: ReactNode }) {
  return (
    <Text
      subdued
      style={{
        fontSize: 10,
        textTransform: "uppercase",
        letterSpacing: "0.02em",
        textAlign: "center",
      }}
    >
      {children}
    </Text>
  );
}

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

  return (
    <AnvilProvider themeData={{ mode }}>
      <Flex direction="column" gap={6}>
        <Flex direction="column" gap={3} style={{ width: "fit-content" }}>
          <Chip
            label="Residential"
            size="small"
            color={RESIDENTIAL_CHIP_COLOR}
          />
          <Flex direction="column" alignItems="center" gap={2}>
            <IllustrationBox
              Illustration={EmptyStateResidentialEvergreenSuccess}
            />
            <TradeLabel>{TRADES_LABEL}</TradeLabel>
          </Flex>
        </Flex>
        <Flex direction="column" gap={3} style={{ width: "fit-content" }}>
          <Chip label="Commercial" size="small" color={COMMERCIAL_CHIP_COLOR} />
          <Flex direction="column" alignItems="center" gap={2}>
            <IllustrationBox
              Illustration={EmptyStateCommercialEvergreenSuccess}
            />
            <TradeLabel>{TRADES_LABEL}</TradeLabel>
          </Flex>
        </Flex>
      </Flex>
    </AnvilProvider>
  );
}

export default App;
```

### Usage Guidance

**When to Use:** Display this illustration when a user successfully completes a workflow or achieves a significant milestone, especially if the task was complex or time-intensive.

**Example scenarios**

* Successfully generating a large customer report
* Completing setup for a new product feature

**Sample copy**

* **Header:** "Toolbox triumph!"
* **Body:** "You nailed it! Your task is complete, and your toolbox is ready for the next project."

> [!TIP]
>
> Keep the copy celebratory so it rewards the effort and reinforces a positive
> feeling about the feature.

## Error State

illustrations-kit-trade-error

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

```tsx lines theme={null}
import type { ComponentType, SVGProps } from "react";
import {
  AnvilProvider,
  Chip,
  Flex,
  Text,
  usePrefersColorScheme,
} from "@servicetitan/anvil2";
import {
  EmptyStateCommercialEmergencyComplianceError,
  EmptyStateCommercialExteriorsError,
  EmptyStateCommercialInteriorsError,
  EmptyStateCommercialMechanicalError,
  EmptyStateCommercialPropertyCareError,
  EmptyStateResidentialEmergencyComplianceError,
  EmptyStateResidentialExteriorsError,
  EmptyStateResidentialInteriorsError,
  EmptyStateResidentialMechanicalError,
  EmptyStateResidentialPropertyCareError,
} from "@servicetitan/anvil2-illustrations";

// Matches the Chip fills from Figma; Chip derives the border and text
// colors from this background automatically via useAccessibleColor.
const RESIDENTIAL_CHIP_COLOR = "#e0f2ff";
const COMMERCIAL_CHIP_COLOR = "#f1edff";

type Trade = {
  label: string;
  Illustration: ComponentType<SVGProps<SVGSVGElement>>;
};

const RESIDENTIAL_TRADES: Trade[] = [
  {
    label: "Property Care",
    Illustration: EmptyStateResidentialPropertyCareError,
  },
  { label: "Exteriors", Illustration: EmptyStateResidentialExteriorsError },
  { label: "Mechanical", Illustration: EmptyStateResidentialMechanicalError },
  {
    label: "Emergency & Compliance",
    Illustration: EmptyStateResidentialEmergencyComplianceError,
  },
  { label: "Interiors", Illustration: EmptyStateResidentialInteriorsError },
];

const COMMERCIAL_TRADES: Trade[] = [
  {
    label: "Property Care",
    Illustration: EmptyStateCommercialPropertyCareError,
  },
  { label: "Exteriors", Illustration: EmptyStateCommercialExteriorsError },
  { label: "Mechanical", Illustration: EmptyStateCommercialMechanicalError },
  {
    label: "Emergency & Compliance",
    Illustration: EmptyStateCommercialEmergencyComplianceError,
  },
  { label: "Interiors", Illustration: EmptyStateCommercialInteriorsError },
];

function TradeRow({
  chipLabel,
  chipColor,
  trades,
}: {
  chipLabel: string;
  chipColor: string;
  trades: Trade[];
}) {
  return (
    <Flex direction="column" gap={3} style={{ width: "fit-content" }}>
      <Chip label={chipLabel} size="small" color={chipColor} />
      <Flex gap={3} alignItems="flex-start">
        {trades.map(({ label, Illustration }) => (
          <Flex key={label} direction="column" alignItems="center" gap={2}>
            <div
              style={{
                height: 116,
                width: 170,
                display: "flex",
                alignItems: "flex-end",
                justifyContent: "center",
              }}
            >
              <Illustration
                aria-hidden="true"
                style={{
                  maxWidth: 170,
                  maxHeight: 116,
                  width: "auto",
                  height: "auto",
                }}
              />
            </div>
            <Text
              subdued
              style={{
                fontSize: 10,
                textTransform: "uppercase",
                letterSpacing: "0.02em",
              }}
            >
              {label}
            </Text>
          </Flex>
        ))}
      </Flex>
    </Flex>
  );
}

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

  return (
    <AnvilProvider themeData={{ mode }}>
      <Flex direction="column" gap={6}>
        <TradeRow
          chipLabel="Residential"
          chipColor={RESIDENTIAL_CHIP_COLOR}
          trades={RESIDENTIAL_TRADES}
        />
        <TradeRow
          chipLabel="Commercial"
          chipColor={COMMERCIAL_CHIP_COLOR}
          trades={COMMERCIAL_TRADES}
        />
      </Flex>
    </AnvilProvider>
  );
}

export default App;
```

### Usage Guidance

**When to Use:** This illustration should appear when the user encounters an error that disrupts their workflow, such as a failed action or system issue.

**Example scenarios**

* An error occurs when submitting a customer invoice
* A scheduling conflict prevents a job from being assigned

**Sample copy**

* **Header:** "The truck hit a snag!"
* **Body:** "Something's not working quite right. Let's get this fixed so you can get back on the road."

> [!TIP]
>
> Include an actionable next step such as Retry or a link to support so the user
> can recover quickly.

## No Search Results State

illustrations-kit-trade-no-search-results

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

```tsx lines theme={null}
import type { ComponentType, SVGProps } from "react";
import {
  AnvilProvider,
  Chip,
  Flex,
  Text,
  usePrefersColorScheme,
} from "@servicetitan/anvil2";
import {
  EmptyStateCommercialEmergencyComplianceNoSearchResults,
  EmptyStateCommercialExteriorsNoSearchResults,
  EmptyStateCommercialInteriorsNoSearchResults,
  EmptyStateCommercialMechanicalNoSearchResults,
  EmptyStateCommercialPropertyCareNoSearchResults,
  EmptyStateResidentialEvergreenNoSearchResults,
  EmptyStateResidentialMechanicalNoSearchResults,
  EmptyStateResidentialPropertyCareNoSearchResults,
} from "@servicetitan/anvil2-illustrations";

// Matches the Chip fills from Figma; Chip derives the border and text
// colors from this background automatically via useAccessibleColor.
const RESIDENTIAL_CHIP_COLOR = "#e0f2ff";
const COMMERCIAL_CHIP_COLOR = "#f1edff";

type Trade = {
  label: string;
  Illustration: ComponentType<SVGProps<SVGSVGElement>>;
};

// Exteriors, Emergency & Compliance, and Interiors share the generic
// residential no-search-results illustration in Figma.
const RESIDENTIAL_TRADES: Trade[] = [
  {
    label: "Property Care",
    Illustration: EmptyStateResidentialPropertyCareNoSearchResults,
  },
  {
    label: "Mechanical",
    Illustration: EmptyStateResidentialMechanicalNoSearchResults,
  },
  {
    label: "Exteriors, Emergency & Compliance, Interiors",
    Illustration: EmptyStateResidentialEvergreenNoSearchResults,
  },
];

const COMMERCIAL_TRADES: Trade[] = [
  {
    label: "Property Care",
    Illustration: EmptyStateCommercialPropertyCareNoSearchResults,
  },
  {
    label: "Exteriors",
    Illustration: EmptyStateCommercialExteriorsNoSearchResults,
  },
  {
    label: "Mechanical",
    Illustration: EmptyStateCommercialMechanicalNoSearchResults,
  },
  {
    label: "Emergency & Compliance",
    Illustration: EmptyStateCommercialEmergencyComplianceNoSearchResults,
  },
  {
    label: "Interiors",
    Illustration: EmptyStateCommercialInteriorsNoSearchResults,
  },
];

function TradeRow({
  chipLabel,
  chipColor,
  trades,
}: {
  chipLabel: string;
  chipColor: string;
  trades: Trade[];
}) {
  return (
    <Flex direction="column" gap={3} style={{ width: "fit-content" }}>
      <Chip label={chipLabel} size="small" color={chipColor} />
      <Flex gap={3} alignItems="flex-start">
        {trades.map(({ label, Illustration }) => (
          <Flex key={label} direction="column" alignItems="center" gap={2}>
            <div
              style={{
                height: 116,
                width: 170,
                display: "flex",
                alignItems: "flex-end",
                justifyContent: "center",
              }}
            >
              <Illustration
                aria-hidden="true"
                style={{
                  maxWidth: 170,
                  maxHeight: 116,
                  width: "auto",
                  height: "auto",
                }}
              />
            </div>
            <Text
              subdued
              style={{
                fontSize: 10,
                textTransform: "uppercase",
                letterSpacing: "0.02em",
                textAlign: "center",
              }}
            >
              {label}
            </Text>
          </Flex>
        ))}
      </Flex>
    </Flex>
  );
}

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

  return (
    <AnvilProvider themeData={{ mode }}>
      <Flex direction="column" gap={6}>
        <TradeRow
          chipLabel="Residential"
          chipColor={RESIDENTIAL_CHIP_COLOR}
          trades={RESIDENTIAL_TRADES}
        />
        <TradeRow
          chipLabel="Commercial"
          chipColor={COMMERCIAL_CHIP_COLOR}
          trades={COMMERCIAL_TRADES}
        />
      </Flex>
    </AnvilProvider>
  );
}

export default App;
```

### Usage Guidance

**When to Use:** This illustration is appropriate when a user performs a search query that yields no results, signaling that they may need to refine their criteria.

**Example scenarios**

* Searching for a job or customer that does not exist
* Filtering for inventory items that are not available

**Sample copy**

* **Header:** "No bones found!"
* **Body:** "Your search didn't fetch any results. Try adjusting your filters or broadening your search terms."

> [!TIP]
>
> Pair the illustration with search tips or filter suggestions so the user can
> refine the query.

## General Recommendations for All Empty States

* **Tone:** Maintain a friendly, supportive tone in all copy. Playful language aligned with the illustration enhances user engagement and reduces frustration.
* **Actionable Steps:** Always include a call-to-action or recovery path, especially for first-use and error states, to guide the user forward.

> **[Empty state pattern guidance](https://anvil.servicetitan.com/docs/patterns/empty-states/web.md)**


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