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

# Tooltip – Code

> Tooltips are floating labels that add quick clarity to an element.

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="tooltip-playground" fullWidth screenshot>
      ```tsx lines expandable theme={null}
      import { Tooltip, Button } from "@servicetitan/anvil2";
      import Info from "@servicetitan/anvil2/assets/icons/material/round/edit.svg";

      function App() {
        return (
          <div style={{ paddingBlockStart: "3rem" }}>
            <Tooltip defaultOpen>
              <Tooltip.Trigger>
                <Button icon={Info}>Hover over me</Button>
              </Tooltip.Trigger>
              <Tooltip.Content>This is a tooltip!</Tooltip.Content>
            </Tooltip>
          </div>
        );
      }

      export default App;
      ```
    </LiveCode>

    ## Common Examples

    The `Tooltip` component is used to add a floating label to an element, usually triggered on hover or focus.

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

    function ExampleComponent() {
      return (
        <Tooltip>
          <Tooltip.Trigger>
            <span>Hover to open</span>
          </Tooltip.Trigger>
          <Tooltip.Content>Tooltip Content</Tooltip.Content>
        </Tooltip>
      );
    }
    ```

    ### Controlling tooltip state

    By default, the open state of a tooltip is managed internally and opens when the trigger element has hover or focus.

    To manually control the open state of the tooltip, use the `open` prop.

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

      function App() {
        const [open, setOpen] = useState(true);

        return (
          <div style={{ paddingBlockStart: "3rem" }}>
            <Flex justifyContent="center">
              <Tooltip open={open}>
                <Tooltip.Trigger>
                  <Button
                    onClick={() => {
                      setOpen((prev) => !prev);
                    }}
                  >
                    Click to toggle
                  </Button>
                </Tooltip.Trigger>
                <Tooltip.Content>This is a tooltip!</Tooltip.Content>
              </Tooltip>
            </Flex>
          </div>
        );
      }

      export default App;
      ```
    </LiveCode>

    ### Adjusting tooltip offset

    In some cases, the context around the tooltip trigger may require the tooltip to render further away from or closer to the trigger.

    In these cases, adjust the `offset` prop, which accepts a number representing pixels.

    <LiveCode showCode example="tooltip-offset" screenshot fullWidth>
      ```tsx lines expandable theme={null}
      import { Tooltip, Card, Button, Text } from "@servicetitan/anvil2";

      function App() {
        return (
          <div style={{ paddingBlockStart: "4rem", paddingInline: "4rem" }}>
            <Card
              gap={4}
              alignItems="center"
              style={{
                background: "var(--background-color-inverted-strong)",
              }}
            >
              <Tooltip offset={24} defaultOpen>
                <Tooltip.Trigger>
                  <Button appearance="primary">Hover over me</Button>
                </Tooltip.Trigger>
                <Tooltip.Content style={{ maxWidth: "20rem" }}>
                  Prevent the tooltip background from getting lost in the card
                  background.
                </Tooltip.Content>
              </Tooltip>
              <Text
                style={{
                  color: "var(--foreground-color-inverted)",
                }}
              >
                Lorem ipsum dolor sit amet.
              </Text>
            </Card>
          </div>
        );
      }

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

  <Tab title="Tooltip Props">
    ```tsx theme={null}
    <Tooltip
      defaultOpen={false}
      disableFlip={false}
      disableShift={false}
      fallbackPlacements={["bottom", "bottom-start"]}
      offset={5}
      open={false}
      placement="top"
      onOpenChange={(open) => console.log(open)}
    >
      <Tooltip.Trigger>
        <span>Hover to open</span>
      </Tooltip.Trigger>
      <Tooltip.Content>Tooltip Content</Tooltip.Content>
    </Tooltip>
    ```

    ## `Tooltip` Props

    The `Tooltip` component is expected to contain both the `Tooltip.Trigger`, which will show the tooltip when hovered and serve as a reference for where the tooltip will be placed, and the `Tooltip.Content`, which defines what content will be shown inside the tooltip itself.

    <ParamField path="defaultOpen" type="boolean" default="false" />

    <ParamField path="delay" type="number" default="100">
      Delay in milliseconds before showing the tooltip.
    </ParamField>

    <ParamField path="disableFlip" type="boolean" default="false" />

    <ParamField path="disableShift" type="boolean" default="false" />

    <ParamField path="fallbackPlacements" type="Placement[]">
      e.g. `["bottom", "bottom-start"]`
    </ParamField>

    <ParamField path="offset" type="number" default="5">
      The distance (in `px`) between the tooltip and trigger.
    </ParamField>

    <ParamField path="onOpenChange" type="(open: boolean) => void" />

    <ParamField path="open" type="boolean">
      Controls the open state of the tooltip (controlled mode).
    </ParamField>

    <ParamField path="openOnHover" type="boolean">
      Changes interaction to use hover instead of focus.
    </ParamField>

    <ParamField path="placement" type={`"top" | "right" | "bottom" | "left" | "top-start" | "top-end" | "right-start" | "right-end" | "bottom-start" | "bottom-end" | "left-start" | "left-end"`} default="top" />
  </Tab>
</Tabs>
