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

# Details – Code

> Details are accordions that show or hide information when clicked.

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="details-playground" fullWidth screenshot>
      ```tsx lines expandable theme={null}
      import { Details } from "@servicetitan/anvil2";

      function App() {
        return (
          <div style={{ maxWidth: "23rem" }}>
            <Details>
              <Details.Summary>Click to see details.</Details.Summary>
              <Details.Content>
                Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
                eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
                minim veniam, quis nostrud exercitation ullamco laboris nisi ut
                aliquip ex ea commodo consequat.
              </Details.Content>
            </Details>
            <Details>
              <Details.Summary>Click to see details.</Details.Summary>
              <Details.Content>
                Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
                eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
                minim veniam, quis nostrud exercitation ullamco laboris nisi ut
                aliquip ex ea commodo consequat.
              </Details.Content>
            </Details>
          </div>
        );
      }

      export default App;
      ```
    </LiveCode>

    ## Common Examples

    ```tsx theme={null}
    import { Details } from "@servicetitan/anvil2";

    function ExampleComponent() {
      return (
        <Details>
          <Details.Summary>Click to expand</Details.Summary>
          <Details.Content>Lorem ipsum dolor sit amet.</Details.Content>
        </Details>
      );
    }
    ```

    ### JSX content in details

    The `children` prop of the `Details` component can accept any `ReactNode`. In many cases, text will be all that is required. In more complex scenarios, other Anvil2 components and JSX can be used.

    <LiveCode showCode example="details-children" screenshot fullWidth>
      ```tsx lines expandable theme={null}
      /* eslint-disable jsx-a11y/anchor-is-valid */
      import { Details, Flex, Text } from "@servicetitan/anvil2";

      function App() {
        return (
          <Details>
            <Details.Summary>Need more help?</Details.Summary>
            <Details.Content>
              <Flex gap="6">
                <div>
                  <Text variant="headline" el="h3">
                    Reach Out
                  </Text>
                  <ul>
                    <li>
                      <a href="#">(800) 555-1234</a>
                    </li>
                    <li>
                      <a href="#">help@acmeplumbing.com</a>
                    </li>
                  </ul>
                </div>
                <div>
                  <Text variant="headline" el="h3">
                    Useful Links
                  </Text>
                  <ul>
                    <li>
                      <a href="#">acmeplumbing.com/help</a>
                    </li>
                    <li>
                      <a href="#">acmeplumbing.com/faqs</a>
                    </li>
                  </ul>
                </div>
              </Flex>
            </Details.Content>
          </Details>
        );
      }

      export default App;
      ```
    </LiveCode>

    ### Controlling details

    By default, the `Details` component is uncontrolled and expands/collapses based on user input (on click or on enter or space key press when the element is focused). Use the `expanded` prop to control the details expanded state programatically.

    <LiveCode showCode example="details-expanded" screenshot fullWidth>
      ```tsx lines expandable theme={null}
      import { Details, Flex, Button } from "@servicetitan/anvil2";
      import { useState } from "react";

      function App() {
        const [expanded, setExpanded] = useState(false);
        const toggleExpanded = () => {
          setExpanded((prev) => !prev);
        };

        return (
          <Flex justifyContent="space-between">
            <Button onClick={toggleExpanded}>Toggle expanded</Button>
            <Details expanded={expanded} onClick={toggleExpanded}>
              <Details.Summary>Click to see details</Details.Summary>
              <Details.Content>Lorem ipsum dolor sit amet.</Details.Content>
            </Details>
          </Flex>
        );
      }

      export default App;
      ```
    </LiveCode>

    ### Accordions

    To create an accordion-style details list, control the open state of each item using the `expanded` on `onClick` props.

    <LiveCode showCode example="details-accordion" screenshot fullWidth>
      ```tsx lines expandable theme={null}
      import { Details, type DetailsProps } from "@servicetitan/anvil2";
      import { useState } from "react";

      function App() {
        const [expanded, setExpanded] = useState<string | undefined>("2");
        const expandDetails = (id: DetailsProps["id"]) => {
          setExpanded((prev) => (prev === id ? undefined : id));
        };

        return (
          <div style={{ maxWidth: "23rem" }}>
            <Details
              id="1"
              expanded={expanded === "1"}
              onClick={() => expandDetails("1")}
            >
              <Details.Summary>One open at a time Details</Details.Summary>
              <Details.Content>
                Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
                eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
                minim veniam, quis nostrud exercitation ullamco laboris nisi ut
                aliquip ex ea commodo consequat.
              </Details.Content>
            </Details>
            <Details
              id="2"
              expanded={expanded === "2"}
              onClick={() => expandDetails("2")}
            >
              <Details.Summary>One open at a time Details</Details.Summary>
              <Details.Content>
                Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
                eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
                minim veniam, quis nostrud exercitation ullamco laboris nisi ut
                aliquip ex ea commodo consequat.
              </Details.Content>
            </Details>
            <Details
              id="3"
              expanded={expanded === "3"}
              onClick={() => expandDetails("3")}
            >
              <Details.Summary>One open at a time Details</Details.Summary>
              <Details.Content>
                Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
                eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
                minim veniam, quis nostrud exercitation ullamco laboris nisi ut
                aliquip ex ea commodo consequat.
              </Details.Content>
            </Details>
          </div>
        );
      }

      export default App;
      ```
    </LiveCode>

    ### Details content height options

    The following props are available to control the height of the details content: `height` and `maxHeight`. If either is set, the content element will also have `overflow: auto`.

    <LiveCode showCode example="details-height" screenshot fullWidth>
      ```tsx lines expandable theme={null}
      import { Details } from "@servicetitan/anvil2";

      function App() {
        return (
          <div style={{ maxWidth: "23rem" }}>
            <Details defaultExpanded>
              <Details.Summary>
                <code>height=&quot;5rem&quot;</code>
              </Details.Summary>
              <Details.Content height="5rem">
                This container scrolls!
                <br />
                Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
                eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
                minim veniam, quis nostrud exercitation ullamco laboris nisi ut
                aliquip ex ea commodo consequat.
              </Details.Content>
            </Details>
            <Details defaultExpanded>
              <Details.Summary>
                <code>height={80}</code>
              </Details.Summary>
              <Details.Content
                height={80}
                style={{ background: "var(--background-color-primary-subdued)" }}
              >
                This container is always <code>80px</code>.
              </Details.Content>
            </Details>
          </div>
        );
      }

      export default App;
      ```
    </LiveCode>

    <LiveCode showCode example="details-maxheight" screenshot fullWidth>
      ```tsx lines expandable theme={null}
      import { Details } from "@servicetitan/anvil2";

      function App() {
        return (
          <div style={{ maxWidth: "23rem" }}>
            <Details defaultExpanded>
              <Details.Summary>
                <code>maxHeight=&quot;5rem&quot;</code>
              </Details.Summary>
              <Details.Content maxHeight="5rem">
                This container scrolls! <br />
                Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
                eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad
                minim veniam, quis nostrud exercitation ullamco laboris nisi ut
                aliquip ex ea commodo consequat.
              </Details.Content>
            </Details>
            <Details defaultExpanded>
              <Details.Summary>
                <code>maxHeight={80}</code>
              </Details.Summary>
              <Details.Content maxHeight={80}>
                This container shrinks to fit content under <code>80px</code>.
              </Details.Content>
            </Details>
          </div>
        );
      }

      export default App;
      ```
    </LiveCode>
  </Tab>

  <Tab title="Details Props">
    ```tsx theme={null}
    <Details defaultExpanded={false} expanded={false}>
      <Details.Summary>Click to expand</Details.Summary>
      <Details.Content>Content here</Details.Content>
    </Details>
    ```

    ## `Details` Props

    <ParamField path="defaultExpanded" type="boolean" default="false">
      Controls the default expanded state for uncontrolled details.
    </ParamField>

    <ParamField path="expanded" type="boolean" default="false">
      Controls the expanded state for controlled details.
    </ParamField>
  </Tab>

  <Tab title="Details.Content Props">
    ```tsx theme={null}
    <Details.Content height="200px" maxHeight="400px">
      Content here
    </Details.Content>
    ```

    ## `Details.Content` Props

    <ParamField path="height" type="string | number" />

    <ParamField path="maxHeight" type="string | number" />
  </Tab>

  <Tab title="Details.Summary Props">
    ```tsx theme={null}
    <Details.Summary onClick={() => console.log("Clicked")}>
      Click to expand
    </Details.Summary>
    ```

    ## `Details.Summary` Props

    The `Details.Summary` component can accept any valid HTML button props.
  </Tab>
</Tabs>
