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

# Drilldown – Code

> A Drilldown is a navigation pattern that allows users to view additional information within the same container. Drilldown is a helper that works with the Drawer, Dialog, and Page Panel components.

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

<Tabs>
  <Tab title="Implementation">
    <LiveCode showCode example="drilldown-options-drawer" fullWidth>
      ```tsx lines expandable theme={null}
      import {
        Drawer,
        DrillDown,
        useDrillDown,
        Button,
        Flex,
      } from "@servicetitan/anvil2";
      import { useLayoutEffect } from "react";

      function App() {
        const { drillDownProps, setIndex, back, next } = useDrillDown();

        // Set the initial index after components have registered
        useLayoutEffect(() => {
          setTimeout(() => {
            setIndex(1);
          }, 400);
        }, [setIndex]);

        return (
          <Drawer {...drillDownProps} open size="medium" defaultDrillDownIndex={1}>
            <Drawer.Header>Drawer Header</Drawer.Header>
            <Drawer.Content>
              <Flex direction="column" gap="2">
                <div>This is the drawer body content.</div>
                <Button onClick={() => setIndex(0)}>Set index to 0</Button>
                <Button onClick={() => setIndex(1)}>Set index to 1</Button>
              </Flex>
            </Drawer.Content>
            <Drawer.Footer>
              <Flex gap="3" justifyContent="flex-end">
                <Drawer.CancelButton>Cancel</Drawer.CancelButton>
                <Button appearance="primary">Continue</Button>
              </Flex>
            </Drawer.Footer>

            <DrillDown index={0}>
              <DrillDown.Header>DrillDown Index 0</DrillDown.Header>
              <DrillDown.Content>
                Tempor nisi culpa consectetur enim laborum. Sunt labore pariatur qui
                proident reprehenderit velit minim consequat magna dolor est minim. Ad
                dolor quis do ea velit. Velit quis consequat aute qui nulla et cillum
                nostrud pariatur dolor ut. Sunt ullamco exercitation deserunt ad elit.
                Est incididunt cillum nisi sint reprehenderit reprehenderit labore
                mollit ex sint veniam. Consectetur duis quis magna amet incididunt
                fugiat. Ex irure elit dolore culpa. Culpa nostrud proident cupidatat
                amet est dolore occaecat proident adipisicing incididunt ipsum. Esse
                ipsum pariatur voluptate fugiat eu ut incididunt laboris sint eu irure
                sint elit aliquip. Sit sunt duis ut ut consequat labore nostrud
                pariatur excepteur Lorem quis reprehenderit. Elit fugiat mollit
                excepteur labore ullamco adipisicing veniam nulla. Voluptate
                consectetur excepteur commodo cillum officia laboris aliquip mollit.
                In nisi non cillum proident eu eiusmod ex incididunt cupidatat dolor
                deserunt do culpa ad. Cupidatat cillum proident dolore eu fugiat
                reprehenderit elit esse. Et nostrud sunt anim excepteur enim in do
                dolor ut. Ea officia ex ex veniam incididunt. Amet eu sit est Lorem
                mollit. Amet voluptate officia commodo voluptate et sint do esse ad
                incididunt elit eu. Ex sint voluptate aute et ea. Incididunt enim anim
                aliqua excepteur ea pariatur nisi ullamco officia id. Nisi dolor qui
                ipsum cillum do qui commodo consequat cillum occaecat. Aliqua proident
                sunt do est ut sunt nulla esse eu excepteur tempor occaecat
                incididunt. Velit laborum quis do exercitation aliqua mollit. Aute ex
                tempor adipisicing laboris sunt non dolor ullamco aliqua eiusmod
                cupidatat id et fugiat. Laboris non excepteur anim deserunt proident
                ullamco dolore cupidatat. Cupidatat excepteur Lorem laboris ut aliquip
                do est commodo Lorem enim voluptate. Consectetur sunt et cupidatat
                aliquip amet pariatur Lorem eu laboris duis exercitation exercitation
                culpa non. Amet proident velit veniam ad sunt est ea fugiat enim quis
                cupidatat labore. Amet cillum tempor voluptate et pariatur eiusmod
                magna eu. Velit minim occaecat nisi eiusmod magna ex nostrud minim
                voluptate aute quis fugiat do. Esse excepteur nulla dolore sunt sit
                esse. Minim aliqua adipisicing laborum et non esse dolor incididunt.
                Incididunt quis duis velit pariatur cillum excepteur laboris. Laboris
                velit et ut dolore incididunt ad ipsum excepteur magna enim. Sint enim
                aute velit ea veniam nisi qui culpa. Proident proident ea occaecat ut
                ea. Quis reprehenderit sit ea mollit. Cillum proident qui commodo sint
                consectetur eiusmod anim irure eiusmod. Nisi occaecat irure anim anim
                officia ut est. Ullamco reprehenderit anim dolore ut sit velit. Nisi
                anim quis adipisicing aliqua veniam do. Veniam sint irure pariatur
                adipisicing culpa. Laboris nulla cillum nisi nulla sit mollit eu ipsum
                magna tempor magna sit. Cupidatat qui amet incididunt quis amet eu
                nostrud culpa irure laborum laborum eu. Consequat dolore fugiat
                commodo consequat pariatur. Aliqua id et officia culpa tempor tempor
                dolore in. Consectetur ad id qui eiusmod ullamco velit nulla velit
                cupidatat exercitation tempor excepteur commodo. Duis labore et id id.
                Voluptate mollit non nulla nisi ad nostrud non nisi dolore officia.
                Veniam irure in eu enim reprehenderit qui ullamco nulla aliquip et
                irure irure ad.
              </DrillDown.Content>
              <DrillDown.Footer>
                <Flex gap="3" justifyContent="flex-end">
                  <Button onClick={back}>Cancel</Button>
                  <Button appearance="primary" onClick={next}>
                    Continue
                  </Button>
                </Flex>
              </DrillDown.Footer>
            </DrillDown>

            <DrillDown index={1}>
              <DrillDown.Header>Drilldown Header</DrillDown.Header>
              <DrillDown.Content>Content of Drilldown</DrillDown.Content>
              <DrillDown.Footer>
                <Flex gap="3" justifyContent="flex-end">
                  <Button onClick={back}>Back</Button>
                  <Button appearance="primary" onClick={next}>
                    Continue
                  </Button>
                </Flex>
              </DrillDown.Footer>
            </DrillDown>
          </Drawer>
        );
      }

      export default App;
      ```
    </LiveCode>

    ## Common Examples

    ```tsx theme={null}
    import { Button, Dialog, DrillDown, Flex } from "@servicetitan/anvil2";

    function ExampleComponent() {
      return (
        <Dialog>
          <Dialog.Header>Dialog Header</Dialog.Header>
          <Dialog.Content>This is the dialog body content.</Dialog.Content>
          <Dialog.Footer>
            <Flex gap="3" justifyContent="flex-end">
              <Dialog.CancelButton>Cancel</Dialog.CancelButton>
              <Button appearance="primary">Continue</Button>
            </Flex>
          </Dialog.Footer>
          <DrillDown index={0}>
            <DrillDown.Header>DrillDown Index 0</DrillDown.Header>
            <DrillDown.Content>This is the drilldown body content.</DrillDown.Content>
            <DrillDown.Footer>
              <Flex gap="3" justifyContent="flex-end">
                <DrillDown.PrevButton>Cancel</DrillDown.PrevButton>
                <DrillDown.NextButton appearance="primary">
                  Continue
                </DrillDown.NextButton>
              </Flex>
            </DrillDown.Footer>
          </DrillDown>
        </Dialog>
      );
    }
    ```

    ### Use as children of `Dialog`, `Drawer`, or `Page.Panel`

    Any number of `DrillDown` components can be added as children of the `Dialog`, `Drawer`, or `Page.Panel` component. When a `DrillDown` is visible, it will cover the entire contents of the `Dialog` or `Drawer`.

    ```tsx theme={null}
    <Dialog>
      <Dialog.Header>{...}</Dialog.Header>
      <Dialog.Content>{...}</Dialog.Content>
      <Dialog.Footer>{...}</Dialog.Footer>

      <DrillDown index={0}>{...}</DrillDown>
      <DrillDown index={1}>{...}</DrillDown>
      <DrillDown index={2}>{...}</DrillDown>
      <DrillDown index={3}>{...}</DrillDown>
    </Dialog>
    ```

    ```tsx theme={null}
    <Drawer>
      <Drawer.Header>{...}</Drawer.Header>
      <Drawer.Content>{...}</Drawer.Content>
      <Drawer.Footer>{...}</Drawer.Footer>

      <DrillDown index={0}>{...}</DrillDown>
      <DrillDown index={1}>{...}</DrillDown>
      <DrillDown index={2}>{...}</DrillDown>
      <DrillDown index={3}>{...}</DrillDown>
    </Drawer>
    ```

    <Note>
      **Each `DrillDown` requires a unique `index`**

      `DrillDown` sibling components are identified by their `index` prop. Numbers used for the `index` prop are zero-based, and calling `next` or clicking the `DrillDown.NextButton` will display the next index in numerical order.
    </Note>

    ### Uncontrolled usage

    ```tsx theme={null}
    import { Drawer, Drilldown } from "@servicetitan/anvil2";

    function ExampleComponent() {
      const [isOpen, setIsOpen] = useState(true);

      return (
        <Drawer open={isOpen} onClose={() => setIsOpen(false)}>
          <Drawer.Header>Drawer Header</Drawer.Header>
          <Drawer.Content>This is the drawer body content.</Drawer.Content>
          <Drawer.Footer>
            <Flex gap="3" justifyContent="flex-end">
              <Drawer.CancelButton>Cancel</Drawer.CancelButton>
              <DrillDown.NextButton appearance="primary">Continue</DrillDown.NextButton>
            </Flex>
          </Drawer.Footer>

          <DrillDown index={0} onClose={() => setIsOpen(false)}>
            <DrillDown.Header>DrillDown Index 0</DrillDown.Header>
            <DrillDown.Content>This is the drilldown body content.</DrillDown.Content>
            <DrillDown.Footer>
              <Flex gap="3" justifyContent="flex-end">
                <DrillDown.PrevButton>Cancel</DrillDown.PrevButton>
                <DrillDown.NextButton appearance="primary">
                  Continue
                </DrillDown.NextButton>
              </Flex>
            </DrillDown.Footer>
          </DrillDown>
        </Drawer>
      );
    }
    ```

    #### Using `DrillDown.NextButton` and `DrillDown.PrevButton`

    The `DrillDown` can be used with uncontrolled state by using the `DrillDown.NextButton` to move forward to each `DrillDown` `index` in ascending numerical order. The `DrillDown.PrevButton` will similarly move backward in descending numerical order, and will close the `DrillDown` if the current visible `DrillDown` is `index` `0`.

    ### Controlled usage

    ```tsx theme={null}
    import { Drawer, Drilldown } from "@servicetitan/anvil2";

    function ExampleComponent() {
      const { drillDownProps, back, next } = useDrillDown();
      const [isOpen, setIsOpen] = useState(true);

      return (
        <Drawer {...drillDownProps} open={isOpen} onClose={() => setIsOpen(false)}>
          <Drawer.Header>Drawer Header</Drawer.Header>
          <Drawer.Content>This is the drawer body content.</Drawer.Content>
          <Drawer.Footer>
            <Flex gap="3" justifyContent="flex-end">
              <Drawer.CancelButton>Cancel</Drawer.CancelButton>
              <Button appearance="primary" onClick={next}>Continue</Button>
            </Flex>
          </Drawer.Footer>

          <DrillDown index={0} onClose={() => setIsOpen(false)}>
            <DrillDown.Header>DrillDown Index 0</DrillDown.Header>
            <DrillDown.Content>This is the drilldown body content.</DrillDown.Content>
            <DrillDown.Footer>
              <Flex gap="3" justifyContent="flex-end">
                <Button onClick={back}>Cancel</Button>
                <Button appearance="primary" onClick={next}>
                  Continue
                </Button>
              </Flex>
            </DrillDown.Footer>
          </DrillDown>
        </Drawer>
      );
    }
    ```

    #### Using the `useDrillDown` hook

    The `useDrillDown` hook returns a `next` and `back` function to allow for programmatically navigating between `DrillDown` components in numerical `index` order. (The hook also returns a `setIndex` function to allow navigating to arbitrary `index` values.)

    To allow this hook to work, the `drillDownProps` return value also needs to be spread onto the parent component.

    ```tsx theme={null}
    import { Drawer, Drilldown } from "@servicetitan/anvil2";

    function ExampleComponent() {
      const { drillDownProps, back, next } = useDrillDown();
      const [isOpen, setIsOpen] = useState(true);

      return (
        <Drawer {...drillDownProps} open={isOpen} onClose={() => setIsOpen(false)}>
          {...}
        </Drawer>
      );
    }
    ```

    ### Closing from within a `DrillDown`

    By default, the `DrillDown.Header` does not display a close button. To display a close button in the `DrillDown.Header`, add an `onClose` handler to the `DrillDown`.

    ```tsx theme={null}
    <DrillDown index={0} onClose={() => setOpen(false)}>
      <DrillDown.Header>DrillDown Index 0</DrillDown.Header>
      <DrillDown.Content>This is the drilldown body content.</DrillDown.Content>
      <DrillDown.Footer>
        <Flex gap="3" justifyContent="flex-end">
          <DrillDown.PrevButton>Cancel</DrillDown.PrevButton>
          <DrillDown.NextButton appearance="primary">
            Continue
          </DrillDown.NextButton>
        </Flex>
      </DrillDown.Footer>
    </DrillDown>
    ```
  </Tab>

  <Tab title="DrillDown Props">
    ```tsx theme={null}
    <DrillDown index={0} onClose={() => setOpen(false)}>
      <DrillDown.Header>DrillDown Index 0</DrillDown.Header>
      <DrillDown.Content>This is the drilldown body content.</DrillDown.Content>
      <DrillDown.Footer>
        <Flex gap="3" justifyContent="flex-end">
          <DrillDown.PrevButton>Cancel</DrillDown.PrevButton>
          <DrillDown.NextButton appearance="primary">
            Continue
          </DrillDown.NextButton>
        </Flex>
      </DrillDown.Footer>
    </DrillDown>
    ```

    ## `DrillDown` Props

    In addition to the props listed below, the `DrillDown` component can accept any valid HTML `div` props.

    <ParamField path="index" type="number" required>
      The index of the `DrillDown` screen in the navigation sequence. This index is zero-based.
    </ParamField>

    <ParamField path="onClose" type="() => void">
      Called when the close button in the header is clicked. The close button is only displayed in the `DrillDown.Header` if there is an `onClose` provided.
    </ParamField>
  </Tab>

  <Tab title="DrillDown.Header Props">
    ```tsx theme={null}
    <DrillDown.Header>DrillDown Header</DrillDown.Header>
    ```

    ## `DrillDown.Header` Props

    In addition to the props listed below, the `DrillDown.Header` component can accept any valid HTML`header` props.

    <ParamField path="el" type="&#x22;h1&#x22; | &#x22;h2&#x22; | &#x22;h3&#x22; | &#x22;h4&#x22; | &#x22;h5&#x22; | &#x22;h6&#x22;" default="h1">
      Customizes the heading level of the `DrillDown.Header`
    </ParamField>
  </Tab>

  <Tab title="DrillDown.Content Props">
    ```tsx theme={null}
    <DrillDown.Content>DrillDown content</DrillDown.Content>
    ```

    ## `DrillDown.Content` Props

    The `DrillDown.Content` component can accept any valid HTML `div` props.
  </Tab>

  <Tab title="DrillDown.Footer Props">
    ```tsx theme={null}
    <DrillDown.Footer>
      <Flex gap="3" justifyContent="flex-end">
        <Button onClick={back}>Back</Button>
        <Button appearance="primary" onClick={next}>
          Continue
        </Button>
      </Flex>
    </DrillDown.Footer>
    ```

    ## `DrillDown.Footer` Props

    The `DrillDown.Footer` component can accept any valid HTML `footer` props.
  </Tab>

  <Tab title="DrillDown.NextButton Props">
    ```tsx theme={null}
    <DrillDown.NextButton appearance="primary">
      Continue
    </DrillDown.NextButton>
    ```

    ## `DrillDown.NextButton` Props

    The `DrillDown.NextButton` component can accept the same props as the `Button` component. This button takes the user to the next DrillDown index (e.g. if the `index` `1` `DrillDown` is visible, it will move to `index` `2`).
  </Tab>

  <Tab title="DrillDown.PrevButton Props">
    ```tsx theme={null}
    <DrillDown.PrevButton>
      Back
    </DrillDown.PrevButton>
    ```

    ## `DrillDown.PrevButton` Props

    The `DrillDown.PrevButton` component can accept the same props as the `Button` component. This button takes the user to the previous DrillDown. If there is no previous `DrillDown`, it will close the `DrillDown`.
  </Tab>

  <Tab title="useDrillDown hook">
    ```tsx theme={null}
    const { drillDownProps, setIndex, back, next } = useDrillDown();
    ```

    ## `useDrillDown` hook

    The `useDrillDown` hook returns four values:

    <ParamField path="drillDownProps" type="object">
      This object is required to be spread on the parent component (`Drawer`, `Dialog`) for the `DrillDown` to work in a controlled manner using the `useDrillDown` hook.
    </ParamField>

    <ParamField path="next" type="() => void">
      Calling this function takes the user to the next DrillDown index (e.g. if the `index` `1` `DrillDown` is visible, it will move to `index` `2`).
    </ParamField>

    <ParamField path="back" type="() => void">
      Calling this function takes the user to the previous DrillDown. If there is no previous `DrillDown`, it will close the `DrillDown`.
    </ParamField>

    <ParamField path="setIndex" type="(index: number | undefined) => void">
      Calling this function takes the user to the DrillDown index that is passed into the function. If `setIndex` is called with `undefined`, it will close the `DrillDown`.
    </ParamField>
  </Tab>
</Tabs>
