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

# Checkbox – Design

> Checkboxes are form elements that allow users to select one or more options.

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

export const CodePreviewPlaceholder = ({double, fullWidth}) => {
  const single = <div style={{
    width: fullWidth ? "100%" : "50%",
    borderRadius: "1rem",
    display: "flex",
    padding: "1rem",
    flexDirection: "column",
    gap: "0.5rem",
    height: "10rem",
    marginBlockEnd: "1rem"
  }} className="border-width-default border-color-subdued">
      <div className="bg-strong border-radius-large" style={{
    width: "100%",
    flexGrow: "1"
  }} />
      <div className="bg-strong border-radius-large" style={{
    width: "100%",
    flexGrow: "1"
  }} />
    </div>;
  return double ? <div style={{
    display: "flex",
    gap: "1rem"
  }}>
      {single}
      {single}
    </div> : single;
};

<Frame>
  <div className="w-full h-full bg-[#FFFFFF] p-2 rounded flex items-center justify-center">
    <img noZoom src="https://mintcdn.com/servicetitan/uz2PQSvO75TRhQ38/images/docs/web/components/shared/overview-of-a-checkbox.png?fit=max&auto=format&n=uz2PQSvO75TRhQ38&q=85&s=68aac46a0454d9aec0890f442bf369df" width="228" height="177" data-path="images/docs/web/components/shared/overview-of-a-checkbox.png" />
  </div>
</Frame>

## Anatomy

The Checkbox consists of two primary elements that work together to allow users to select one or more options.

<Frame>
  <div className="w-full h-full bg-[#FFFFFF] p-2 rounded flex items-center justify-center">
    <img
      src="https://mintcdn.com/servicetitan/Ni0bXIw9diilEZPZ/images/docs/web/components/checkbox/design/anatomy-of-checkboxes.png?fit=max&auto=format&n=Ni0bXIw9diilEZPZ&q=85&s=4012f597dc16f63547aea3337a23d2c9"
      alt="Anatomy of
Checkboxes"
      width="656"
      height="178"
      data-path="images/docs/web/components/checkbox/design/anatomy-of-checkboxes.png"
    />
  </div>
</Frame>

1. Checkbox
2. Label

## Options

The Checkbox supports selection states and description configurations to accommodate various form scenarios.

### Selection

<LiveCode example="checkbox-default" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Checkbox } from "@servicetitan/anvil2";

  function App() {
    return (
      <Checkbox.Group legend="Group label">
        <Checkbox label="Unselected" />
        <Checkbox label="Selected" defaultChecked />
        <Checkbox label="Indeterminate" indeterminate />
      </Checkbox.Group>
    );
  }

  export default App;
  ```
</LiveCode>

Checkboxes can be unselected, selected, or indeterminate. Indeterminate checkboxes represent selected and non-selected values.

### Description

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

  function App() {
    return <Checkbox label="Label" description="Description text" />;
  }

  export default App;
  ```
</LiveCode>

Descriptions provide information to help the user avoid errors.

## Behavior

The Checkbox responds to user interaction with distinct visual states and flexible overflow handling.

### Visual States

#### Default

<LiveCode example="checkbox-default" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Checkbox } from "@servicetitan/anvil2";

  function App() {
    return (
      <Checkbox.Group legend="Group label">
        <Checkbox label="Unselected" />
        <Checkbox label="Selected" defaultChecked />
        <Checkbox label="Indeterminate" indeterminate />
      </Checkbox.Group>
    );
  }

  export default App;
  ```
</LiveCode>

#### Disabled

<LiveCode example="checkbox-disabled" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Checkbox } from "@servicetitan/anvil2";

  function App() {
    return (
      <Checkbox.Group legend="Group label">
        <Checkbox label="Unselected" disabled />
        <Checkbox label="Selected" disabled defaultChecked />
        <Checkbox label="Indeterminate" disabled indeterminate />
      </Checkbox.Group>
    );
  }

  export default App;
  ```
</LiveCode>

#### Error

<LiveCode example="checkbox-error" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Checkbox } from "@servicetitan/anvil2";

  function App() {
    return (
      <Checkbox.Group legend="Group label">
        <Checkbox label="Unselected" error />
        <Checkbox label="Selected" error defaultChecked />
        <Checkbox label="Indeterminate" error indeterminate />
      </Checkbox.Group>
    );
  }

  export default App;
  ```
</LiveCode>

### Overflow

<LiveCode example="checkbox-overflow" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Checkbox } from "@servicetitan/anvil2";

  function App() {
    return (
      <div style={{ width: "165px" }}>
        <Checkbox.Group legend="A longer legend that will wrap">
          <Checkbox label="Subscribe to weekly newsletter" />
        </Checkbox.Group>
      </div>
    );
  }

  export default App;
  ```
</LiveCode>

When a Checkbox label is too long for the available space, it will wrap to a new line.

## Usage Guidelines

Use the Checkbox when allowing users to make zero, one, multiple, or all selections from a range of options.

### When to Use

Checkboxes give users a way to make zero, one, multiple, or all selections from a range of options.

### Alternatives

#### Checkbox vs Combobox

Checkbox groups and the Combobox both allow multi-selection of a set of items. Checkbox groups should be used when there are only a few options. For larger options, Checkbox groups can still be used when there is space available and discovery of options is important. Comboboxes are good for 8 or more options and also when conserving space.

#### Checkbox vs Switch

Switches are used for making a selection between two mutually exclusive options and have an immediate effect. Checkboxes allow users to make zero to many choices from available options and changes are not immediate.

#### Checkbox vs Radio vs Switch

Radio buttons are used to select a single option from a set of mutually exclusive options. Checkboxes are best used to make zero to many selections from available options.

|                                                                              | Checkbox                            | Switch                    | Radio                               |
| ---------------------------------------------------------------------------- | ----------------------------------- | ------------------------- | ----------------------------------- |
| When is the selection executed?                                              | After a user clicks a submit button | Immediately               | After a user clicks a submit button |
| How many options are available?                                              | 1 or more                           | 1                         | 2 or more                           |
| Must an option be reducible to an on or off context?                         | No, it can be other things.         | Yes                       | No, it can be other things.         |
| If I had a group of this UI, what is the relation of each item in the group? | Independent of each other           | Independent of each other | Mutually exclusive                  |
| Indeterminate state possible?                                                | Yes                                 | No                        | No                                  |

### How to Use

#### Checkbox Groups

Sets of related Checkboxes should be grouped together in a Checkbox Group. In most cases, a Checkbox Group should have a label. Checkbox Groups allow users to see all available options that are related to each other.

## Content

Content within the Checkbox should clearly communicate the option being selected and provide necessary context.

### Give a descriptive, action-oriented label

The user relies on the label to provide context and identify what the checkbox controls. Use positive and active wording for checkbox labels. Include a verb to prompt the user to take action.

Use sentence case (capitalize only the first word and proper nouns) so control labels are easy to scan. Do not use periods for short phrases or single sentences.

Checkbox labels should follow the content guidelines for labels.

<LiveCode example="checkbox-action-oriented-do" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Checkbox, Flex } from "@servicetitan/anvil2";

  function App() {
    return (
      <Flex direction="column" gap="2">
        <Checkbox label="I agree to the terms of service" />
        <Checkbox label="Use the technician’s home business unit by default" />
        <Checkbox label="Allow changes" />
      </Flex>
    );
  }

  export default App;
  ```
</LiveCode>

<Check>**Do**</Check>

<LiveCode example="checkbox-action-oriented-dont" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Checkbox, Flex } from "@servicetitan/anvil2";

  function App() {
    return (
      <Flex direction="column" gap="2">
        <Checkbox label="I Agree To The Terms of Service." />
        <Checkbox label="Use the technician’s home business unit by default." />
        <Checkbox label="Disable changes" />
      </Flex>
    );
  }

  export default App;
  ```
</LiveCode>

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

### Give the user the information they need to make an informed decision

When the checkbox label doesn't provide enough information and context for users to make an informed decision, use inline help. Inline help works best because it requires no user interaction and is always visible. Keep inline help to 1-2 sentences.

Use the content guidelines for inline help.

Avoid using a tooltip to communicate this kind of information about an option. It's an additional step for users to mouse over the tooltip to reveal its information, and users can't refer to the tooltip content and take action at the same time.

<LiveCode example="checkbox-inline-help-do" screenshot fullWidth>
  ```tsx lines theme={null}
  import { Checkbox } from "@servicetitan/anvil2";

  function App() {
    return (
      <Checkbox
        id="ex-content"
        label="Enable project labels"
        description="This allows techs to apply and edit project labels given to job records"
      />
    );
  }

  export default App;
  ```
</LiveCode>

<Check>**Do**</Check>

## Keyboard Interaction

Users can navigate the Checkbox using standard keyboard controls.

| Key   | Interaction                   |
| ----- | ----------------------------- |
| Space | Enables the selected Checkbox |
| Tab   | Navigate between Checkboxes   |

### Accessibility

* Checkboxes should have a visible label.
* Checkbox groups must have a legend that describes the group.
* If a Checkbox has an error, Helper Text must be present to describe the nature of the error.

For more guidance on form field labels and context, see [input field context association best practices](/docs/accessibility/labels-and-ctas#input-field-context-association).
