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

# Icon – Code

> Icons act as visual aids to help users complete tasks.

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="icon-playground" fullWidth screenshot>
      ```tsx lines expandable theme={null}
      import { Icon } from "@servicetitan/anvil2";
      import Warning from "@servicetitan/anvil2/assets/icons/material/round/warning.svg";

      function App() {
        return <Icon svg={Warning} size="large" />;
      }

      export default App;
      ```
    </LiveCode>

    ## Common Examples

    ```tsx theme={null}
    import { Icon } from "@servicetitan/anvil2";
    import EditIcon from "@servicetitan/anvil2/assets/icons/material/round/Edit.svg";

    function ExampleComponent() {
      return <Icon svg={EditIcon} color="var(--color-green-300)" size="large" />;
    }
    ```

    ### SVGR Config

    Anvil2 icons are pure SVGs, and require a special loader to properly handle imports and rendering – SVGR. Any project using the `@servicetitan/startup` package version `23.5.0` or later will already have this configured. To use Anvil2 in a standalone app or other project, the SVGR plugin needs to be configured to properly render Anvil2 icons.

    Use the examples below for common build tools. For other build tools, check out the [SVGR docs](https://react-svgr.com/docs/getting-started/) (or the specific build tool docs) for how to update the config object, and be sure to disable the `removeViewbox` option in the `svgoConfig` (see the examples for more details).

    #### Webpack SVGR Config

    ```javascript theme={null}
    {
      loader: "@svgr/webpack",
      options: {
        svgoConfig: {
          plugins: [
            {
              name: "preset-default",
              params: {
                overrides: {
                  removeViewBox: false,
                },
              },
            },
          ],
        },
      },
    }
    ```

    *Learn more about [Webpack loaders](https://webpack.js.org/concepts/loaders).*

    #### Vite SVGR Config

    ```javascript theme={null}
    import svgr from "vite-plugin-svgr";

    export default {
      plugins: [
        svgr({
          svgrOptions: {
            svgoConfig: {
              plugins: [
                {
                  name: "preset-default",
                  params: {
                    overrides: {
                      removeViewBox: false,
                    },
                  },
                },
              ],
            },
          },
        }),
      ],
    };
    ```

    ## React Accessibility

    #### Non-interactive Icons

    Icons that lack interaction and have no accompanying text only need an `aria-label` to describe what the Icon is. If paired with text, no additional elements are needed.

    **Decorative icon paired with a text label**

    `<div><Icon svg={Warning} size="large" /> <BodyText>Label Text</BodyText> </div>`

    **Standalone icon with no text label**

    `<Icon svg={Warning} size="large" aria-label="Warning" />`

    #### Interactive Icons

    Icon can be used to provide indication for users which can be focused or hovered to convey more details. In these use cases, add `tabIndex={0}` to make icon focusable and use Tooltip with it.

    For more guidance on icon accessibility, see [accessible icon usage best practices](/docs/accessibility/media-and-animation#alt-tags-vs-decorative-images).
  </Tab>

  <Tab title="Icon Props">
    ```tsx theme={null}
    <Icon
      svg={EditIcon}
      color="var(--color-green-300)"
      size="large"
      inherit={false}
      aria-label="Edit"
    />
    ```

    ## `Icon` Props

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

    <ParamField path="svg" type="Svg" required>
      Assets passed in using SVGR.
    </ParamField>

    <ParamField path="color" type="string">
      Accepts valid CSS color values, including CSS variables.
    </ParamField>

    <ParamField path="inherit" type="boolean" default="false">
      Allows the icon SVG to inherit its color.
    </ParamField>

    <ParamField path="size" type={`"small" | "medium" | "large" | "xlarge"`} default="medium" />
  </Tab>
</Tabs>
