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

# Errors and Warnings

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

Errors will always occur. This pattern provides general guidelines on how to surface the many types of errors and warnings that occur in the app.

<Frame>
  <div className="w-full h-full bg-[#FFFFFF] p-2 rounded flex items-center justify-center">
    <img
      src="https://mintcdn.com/servicetitan/UmHUvEuYrbSv6t_f/images/docs/web/patterns/shared/error-and-warning-overview.png?fit=max&auto=format&n=UmHUvEuYrbSv6t_f&q=85&s=121f15bf34d5eaa48d7d428834f75fe4"
      alt="Error and warning
overview"
      width="608"
      height="516"
      data-path="images/docs/web/patterns/shared/error-and-warning-overview.png"
    />
  </div>
</Frame>

## Getting Started

When writing an error or warning message, consider these questions:

* **What is the issue?**
  * Knowing what the issue is (or knowing that we don't know) can help frame what to communicate to the user
* **What is the cause of the issue?**
  * Common reasons could be user action, server/network issues, or not being able to find a resource
* **What can the user do to resolve the issue?**
  * If it's the app fault, explain that. If it's user error, can you identify the most likely cause?
* **Is there a path a user can take to resolve the issue?**
  * Whenever it is possible for a user to take action on the issue, a path should be given. For example, if using a Banner or Toast, provide a call to action in them

## Types of errors and warnings

### Anatomy of hint, error, and description text

Form fields should provide helpful information to the user for how they should fill out the field. To understand the anatomy of these elements, read the documentation for [Field Message](/docs/web/components/field-message/design).

### Page-level messages

This error type is used when an error applies to the entire page. They are represented as [Alerts](/docs/web/components/alert/design) that are placed below the page header.

<LiveCode example="errorsandwarnings-header-alert" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Alert, Flex, Button } from "@servicetitan/anvil2";

  function App() {
    return (
      <Flex direction="column" gap="8">
        <Alert title="Fix before posting to batch" status="danger">
          You cannot post invoice #2345 because it has an outdated application for
          payment. Please update all applications in this series and then try
          again.{" "}
        </Alert>
        <Alert
          title="Update your existing applications for payment before adding more."
          status="warning"
        />
        <Alert title="Update the invoice" status="warning">
          Please save the invoice to reflect the changes you made to the
          Application for Payment.
          <Flex gap="3">
            <Button>Save invoice</Button>
            <Button>Not now</Button>
          </Flex>
        </Alert>
      </Flex>
    );
  }

  export default App;
  ```
</LiveCode>

They can be used to:

* Summarize individual errors found on the rest of the page
* Inform the user of important, but non-critical information about the page

##### Errors and Tabs

When [Tabs](/docs/web/components/tab/design) are present, Alerts can be placed either below the Tab or above the Tab depending on how critical it is a user should know about the status. As a rule, place it below the Tabs. Don't represent status directly in the Tabs.

##### Copy Elements

* Bolded Headline
* Sentence explanation & next step
* 1-2 CTAs can be buttons or links (optional)

##### Copy Rules

* Headline should be title case if two words or less, otherwise sentence case
* Sentence(s) should be action focused, active voice, and include next steps for user to take. No links in body
* CTAs should be title case for two words or less, sentence case for more

### Form errors and validation

[Form](/docs/web/patterns/forms) errors are among the most common type of errors. Each individual component page provides specific styling and text location. It is recommended to also use an [Alert](/docs/web/components/alert/design) as a summary when multiple errors exist.

#### Validating on submit

This validation occurs after a user has hit a save or submit button. These errors are paired with [Alerts](/docs/web/components/alert/design) and individual form field errors.

<LiveCode example="errorsandwarnings-form-submit" screenshot fullWidth>
  ```tsx lines theme={null}
  import { TextField, Grid } from "@servicetitan/anvil2";

  function App() {
    return (
      <Grid gap="6">
        <TextField
          label="Hours"
          defaultValue="3"
          error="Maximum hours must be greater than the minimum"
        />

        <TextField
          label="Price"
          defaultValue="-4.50"
          prefix="$"
          error="Value cannot be negative"
        />
      </Grid>
    );
  }

  export default App;
  ```
</LiveCode>

#### Validating before submission

When format requirements exist for a field (such as the `@` in an email input), validating the form element after a user has left focus can help resolve errors.

#### When to use validation before submission:

* When a [Textfield](/docs/web/components/text-field/design) has known formatting requirements. If the requirement is ambiguous to a user (e.g., password requirements), add a [hint](/docs/web/patterns/forms#labels-and-help)
* In the initial user interaction, validate only after a user has left focus on the field and if the user entered anything
* When a user interacts with an errored field, validate after each keystroke. This helps the user identify when the user has met the field requirements

#### When to avoid validation before submission:

* While the user is still interacting with the field
* When a field was left empty by the user
* When it takes at least a second for the codebase to validate the field

##### Copy Elements

* Short fragment or sentence

##### Copy Rules

* Sentence case no punctuation

#### Alert Summary of Error(s)

It is recommended to add an [Alert](/docs/web/components/alert/design) at the top of a form that has errors. If the form is the main content of the page, it follows the page-level guidelines. Otherwise, it appears wherever the top of the form is.

* The [Alert](/docs/web/components/alert/design) should only appear after a validating on submit. Validations before submission do not need an [Alert](/docs/web/components/alert/design)
* The summary should list out each of the errors encountered on the page
* In general, the summary should not be used alone. Inline help should be added when possible

<LiveCode example="errorsandwarnings-form-alert" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Alert, Grid, TextField } from "@servicetitan/anvil2";

  function App() {
    return (
      <Grid gap="6">
        <Alert
          title="Please fix the following elements and submit again"
          status="danger"
        >
          <ul style={{ margin: 0, paddingLeft: "1.5rem" }}>
            <li>Enter a last name</li>
            <li>Enter a valid email address</li>
            <li>Enter a valid area code</li>
          </ul>
        </Alert>
        <Grid gap="6" templateColumns="1fr 1fr">
          <TextField label="First Name" defaultValue="Jane" />
          <TextField label="Last Name" error="Enter a last name" />
        </Grid>
        <TextField
          label="Email Address"
          defaultValue="emailservicetitan.com"
          error="Enter a valid email address"
        />
        <TextField
          label="Phone Number"
          defaultValue="555-5555"
          hint="(xxx) xxx–xxxx"
          error="Enter a valid area code"
        />
      </Grid>
    );
  }

  export default App;
  ```
</LiveCode>

##### Copy Elements

* Bolded Headline
* Sentence explanation & next step

##### Copy Rules

* Headline should be title case if two words or less, otherwise sentence case, no punctuation
* Sentence(s) should be action focused, active voice, and include next steps for user to take
* No links or buttons

### System and network errors

System errors can typically be described as 400 or 500 type errors. If there is a place for it on the page, it is preferred to integrate an Empty State into the section. Otherwise, using a [Toast](/docs/web/components/toast/design) is preferred over components such as the Alert or Announcement.

* When a system error is the apps fault, take responsibility
* If there is an HTTP response, place it at the end of the body content
* When using the Toast to present an error, it should persist on the page
* When it is possible to determine the solution, provide it to the user. For example, a 401 error resulting from not being logged in

##### Copy Elements

* Bolded Headline
* Sentence explanation (optional)
* Button CTA

##### Copy Rules

* Headline should be title case if two words or less, otherwise sentence case
* Sentence(s) should be action focused, active voice, and include next steps for user to take.
* CTAs should be title case for two words or less, sentence case for more

### Application errors and warnings

App-level messages are used to convey a status relevant to the entire experience, represented with an [Announcement](/docs/web/components/announcement/design). These are not used in specific products within the platform. Some examples might include a sandbox environment message and a scheduled downtime notice.

<LiveCode example="errorsandwarnings-application-announcement" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Announcement, Button } from "@servicetitan/anvil2";

  function App() {
    return (
      <Announcement
        status="warning"
        title="Your account needs a default credit card."
        onClose={console.log}
      >
        <Button size="small">Add default card</Button>
      </Announcement>
    );
  }

  export default App;
  ```
</LiveCode>

##### Copy Elements

* Sentences
* Button CTA

##### Copy Rules

* Full sentences with punctuation should be used
* CTA should be title case for two words or less, sentence case for more

### Empty state errors and warnings

Many different contexts for an empty state can exist, some of which can be tied to errors and warnings.

<LiveCode example="errorsandwarnings-empty" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Flex, Icon, Text } from "@servicetitan/anvil2";
  import { core } from "@servicetitan/anvil2/token";
  import NotInterested from "@servicetitan/anvil2/assets/icons/material/round/not_interested.svg";

  function App() {
    return (
      <Flex
        direction="column"
        alignItems="center"
        style={{ maxWidth: "420px", textAlign: "center", margin: "0 auto" }}
      >
        <Icon
          size="xlarge"
          svg={NotInterested}
          style={{ color: core.semantic?.StatusColorDanger?.value }}
        />
        <Text variant="headline" size="medium" el="h1">
          No results found
        </Text>
        <Text variant="body" subdued>
          Try another search or create a new report by clicking the button above.
        </Text>
      </Flex>
    );
  }

  export default App;
  ```
</LiveCode>

##### Copy Elements

* Bolded Headline (optional)
* Sentence(s) explanation
* Button CTA (optional)

##### Copy Rules

* Headline should be title case if two words or less, otherwise sentence case
* Full sentences with punctuation should be used for body copy
* CTA should be title case for two words or less, sentence case for more

## Errors vs Warnings

Anvil provides the option of warning and error statuses across many of its components. Warnings, usually represented in yellow or orange, are a way of providing a less severe notification to users. They are useful when users should be informed of something, but aren’t necessarily required to take action on something.

### Examples where warnings are preferred

* If a user can correct the issue at a later point
* The system detects something might be wrong from a user input
* To signal that significant change may/will happen in the future
* To prevent future errors from occurring.

### Examples where errors are preferred

* If a user cannot proceed in a task without resolving the issue
* When server or network issues arise
* For form validation

## Preventive Measures

While we can’t prevent all errors, we can design interfaces that help minimize user mistakes

### Disabling submission

For simple layouts, the primary action can be disabled until all required fields are filled out, and paired with a [Tooltip](/docs/web/components/tooltip/design) to give the a user a hint. In complex layouts however, a submit-type button can help a user figure out what to do to proceed.

<LiveCode example="errorsandwarnings-disable-submit" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Button, Flex, Tooltip } from "@servicetitan/anvil2";
  import Info from "@servicetitan/anvil2/assets/icons/material/round/info.svg";

  function App() {
    return (
      <Flex gap="3" justifyContent="flex-end">
        <Button>Previous</Button>
        <Button appearance="primary" disabled>
          Next
        </Button>
        <Tooltip placement="top-end">
          <Tooltip.Trigger>
            <Button appearance="ghost" icon={Info} />
          </Tooltip.Trigger>
          <Tooltip.Content>
            Fill out all the fields in the form to proceed
          </Tooltip.Content>
        </Tooltip>
      </Flex>
    );
  }

  export default App;
  ```
</LiveCode>

### Confirmation Dialog

Adding confirmations can be useful to avoiding mistakes. See the [Confirmation](/docs/web/patterns/confirmation) pattern for specific uses.

<LiveCode example="errorsandwarnings-dialog-confirm" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Dialog, Flex, Button } from "@servicetitan/anvil2";

  function App() {
    return (
      <div style={{ padding: "7rem 11.5rem" }}>
        <Dialog open>
          <Dialog.Header>Save for later?</Dialog.Header>
          <Dialog.Content>
            You can always set up this campaign at a later time.
          </Dialog.Content>
          <Dialog.Footer>
            <Flex justifyContent="flex-end">
              <Flex gap="3">
                <Dialog.CancelButton>Cancel</Dialog.CancelButton>
                <Button appearance="primary">Save</Button>
              </Flex>
            </Flex>
          </Dialog.Footer>
        </Dialog>
      </div>
    );
  }

  export default App;
  ```
</LiveCode>

<LiveCode example="errorsandwarnings-dialog-confirm-danger" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Dialog, Flex, Button } from "@servicetitan/anvil2";

  function App() {
    return (
      <div style={{ padding: "7rem 11.5rem" }}>
        <Dialog open>
          <Dialog.Header>Delete email?</Dialog.Header>
          <Dialog.Content>
            Are you sure you want to delete this email and it scheduling interval?
          </Dialog.Content>
          <Dialog.Footer>
            <Flex justifyContent="flex-end">
              <Flex gap="3">
                <Dialog.CancelButton>Cancel</Dialog.CancelButton>
                <Button appearance="danger">Delete</Button>
              </Flex>
            </Flex>
          </Dialog.Footer>
        </Dialog>
      </div>
    );
  }

  export default App;
  ```
</LiveCode>

##### Copy Elements

* Bolded Headline
* Sentence explanation
* Button CTA

##### Copy Rules

* Headline should be sentence case
* Sentence(s) should be action focused, active voice, and include next steps for user to take. No links in body
* CTAs should be title case for two words or less, sentence case for more

### Required labeling

When form field elements are required, the \* can help users identify what they need to fill out.

<LiveCode example="errorsandwarnings-form-required" screenshot fullWidth>
  ```tsx lines theme={null}
  import { TextField, Grid } from "@servicetitan/anvil2";

  function App() {
    return (
      <Grid gap="6">
        <TextField label="Full Name" required />
        <TextField label="Email Address" required />
        <TextField label="Street Address" />
      </Grid>
    );
  }

  export default App;
  ```
</LiveCode>

## Anti-patterns

Some components could theoretically be used to display errors, but should be avoided.

* **Don’t use Dialogs or browser alerts to display errors or warnings.** Unless the content already existed in these overlays, these components should not be used to display errors. These components interrupt, adding an extra step to resolve errors

<LiveCode example="errorsandwarnings-dialog-error-dont" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Dialog, Flex, Button } from "@servicetitan/anvil2";

  function App() {
    return (
      <div style={{ padding: "9rem 11.5rem" }}>
        <Dialog enableScrollChaining open>
          <Dialog.Header>There were errors with the submission</Dialog.Header>
          <Dialog.Content>
            <ul style={{ margin: 0 }}>
              <li>Password must be at least 8 characters.</li>
              <li>Submitted password was used in the last 6 months.</li>
            </ul>
          </Dialog.Content>
          <Dialog.Footer>
            <Flex justifyContent="flex-end">
              <Flex gap="3">
                <Dialog.CancelButton>Cancel</Dialog.CancelButton>
                <Button appearance="primary">Save</Button>
              </Flex>
            </Flex>
          </Dialog.Footer>
        </Dialog>
      </div>
    );
  }

  export default App;
  ```
</LiveCode>

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

Alerts should be used over Dialogs for summaries.

* **Avoid overlay components to display error messages when an inline variation exists.** Tooltips and Popovers can prevent an end user from scanning the content of a page
* **Don’t validate form elements while a user is still interacting with it.** Many form elements do not start off validated correctly (e.g., typing out an email at the start will be missing the @)
* **Avoid Red Buttons to indicate an error.** Red buttons signify that an act is destructive (such as deleting a document or an action that cannot be undone). Other components should be used to signify the presence of an error

## Copy Guidelines

* **Content should be clear and easy to understand.** It should be encouraging without being overly apologetic or humorous
* **Avoid development jargon.** Users are unlikely to be familiar with the inner workings of the app or web development. Frame copy toward user actions and goals, not the underlying software cause of the problem
* **If it's known how to resolve the issue, the copy should explain it.** For example, "Enter a maximum price higher than the minimum price." is more helpful than "Enter a valid maximum price"
* When user action caused the error, avoid outright blame on them
* When the error is caused by the app, accept responsibility and apologize

## Additional resources

* The product content team has additional internal documentation on writing for [Error and other message types](https://servicetitan.atlassian.net/wiki/spaces/DTW/pages/263848031/Error+and+Other+Message+Types+-+Docs).
* [NN Group, How to Report Errors in Forms: 10 Design Guidelines](https://www.nngroup.com/articles/errors-forms-design-guidelines/)
