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

# Dnd – Code

> Dnd is a collection of low-level UI components that can be assembled into a drag and drop UI.

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">
    <Note>
      **Bring your own drag-and-drop interactions.**

      While these components are intended to help you create drag and drop experiences that align with our designs, they do not provide the actual drag-and-drop interactions. You should evaluate external libraries make the best choice for your needs.
    </Note>

    ## Common Examples

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

    ### Zone

    The `Dnd.Zone` can be used to style an element as a drop zone.

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

      function App() {
        return <Dnd.Zone isDragging>your content here</Dnd.Zone>;
      }

      export default App;
      ```
    </LiveCode>

    ### Handle

    The `Dnd.Handle` is an icon which helps users understand that something is draggable.

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

      function App() {
        return <Dnd.Handle />;
      }

      export default App;
      ```
    </LiveCode>

    ### Handle Button

    The `Dnd.HandleButton` is a button-wrapped icon which helps users understand that something is draggable. Use this if your draggable item contains other interactive elements.

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

      function App() {
        return <Dnd.HandleButton isActive />;
      }

      export default App;
      ```
    </LiveCode>

    ### Sort Line

    The `Dnd.SortLine` indicates where an item will be dropped in a sortable list.

    The width of the line is based upon its nearest relatively positioned ancestor.

    This component should be used when you're building an experience that is sortable in one dimension (i.e. vertical or horizontal lists). It is not suitable for sorting two-dimensional sorting (e.g. grids).

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

      function App() {
        return (
          <div style={{ width: "100%", position: "relative" }}>
            <Dnd.SortLine orientation="vertical" position="before" offset="0" />
          </div>
        );
      }

      export default App;
      ```
    </LiveCode>

    ### DndSort

    If you're not looking to create your own entire drag and drop solution, check to see if `DndSort` is capable of supporting your needs. It's a pre-built composition that uses all of these `Dnd` components to cover many basic cases including: sorting a list, arranging items into groups, or both. Read more about that component [here](/docs/web/components/dnd-sort/code).

    ## Best Practices

    ### Draggables with interactivity

    <LiveCode showCode example="dnd-do-interactive" screenshot fullWidth>
      ```tsx lines expandable theme={null}
      import { Dnd, Card, Button } from "@servicetitan/anvil2";

      function App() {
        return (
          <Card gap="4">
            <Dnd.HandleButton />
            <Button>Action</Button>
          </Card>
        );
      }

      export default App;
      ```
    </LiveCode>

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

    If your draggable item has interactive elements, use the Dnd.HandleButton to initiate dragging.

    <LiveCode showCode example="dnd-dont-interactive" screenshot fullWidth>
      ```tsx lines expandable theme={null}
      import { Dnd, Card, Button } from "@servicetitan/anvil2";

      function App() {
        return (
          <Button>
            <Card>
              <Dnd.Handle />
              <Button>Action</Button>
            </Card>
          </Button>
        );
      }

      export default App;
      ```
    </LiveCode>

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

    If your draggable item has interactive elements, don't nest interactive elements.
  </Tab>

  <Tab title="Dnd.Zone Props">
    ```tsx theme={null}
    import { Dnd } from "@servicetitan/anvil2";

    function ExampleComponent() {
    return (

    <Dnd.Zone isOver={false} isValid={false} isDragging={false}>
      {/* Zone content */}
    </Dnd.Zone>
    ); }

    ```

    ## `Dnd.Zone` Props

    <ParamField path="isDragging" type="boolean" required>
      Whether an item is currently being dragged.
    </ParamField>

    <ParamField path="isOver" type="boolean" required>
      Whether an item is currently being dragged over the zone.
    </ParamField>

    <ParamField path="isValid" type="boolean" required>
      Whether the current drag operation is valid for this zone.
    </ParamField>

    <ParamField path="children" type="ReactNode">
      Child elements to render inside the zone.
    </ParamField>

    <ParamField path="className" type="string">
      Optional CSS class name to apply to the zone.
    </ParamField>

    <ParamField path="el" type="ElementType" default="div">
      The HTML element type to render.
    </ParamField>

    All props for the specified element type are also supported.
  </Tab>

  <Tab title="Dnd.Handle Props">
    ```tsx theme={null}
    import { Dnd } from "@servicetitan/anvil2";

    function ExampleComponent() {
      return <Dnd.Handle />;
    }
    ```

    ## `Dnd.Handle` Props

    <ParamField path="className" type="string">
      Optional CSS class name to apply to the handle
    </ParamField>
  </Tab>

  <Tab title="Dnd.HandleButton Props">
    ```tsx theme={null}
    import { Dnd } from "@servicetitan/anvil2";

    function ExampleComponent() {
    return <Dnd.HandleButton isActive={false} />;
    }

    ```

    ## `Dnd.HandleButton` Props

    In addition to the props listed below, the `Dnd.HandleButton` component can accept any [`ButtonCompound`](/docs/web/components/button/design#anatomy) props.

    <ParamField path="className" type="string">
      Optional CSS class name to apply to the button
    </ParamField>

    <ParamField path="isActive" type="boolean" default="false">
      Whether the handle is currently being dragged
    </ParamField>
  </Tab>

  <Tab title="Dnd.SortLine Props">
    ```tsx theme={null}
    import { Dnd } from "@servicetitan/anvil2";

    function ExampleComponent() {
      return (
        <Dnd.SortLine
          orientation="vertical"
          position="before"
          offset="-2px"
        />
      );
    }
    ```

    ## `Dnd.SortLine` Props

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

    <ParamField path="offset" type="string">
      The offset of the line from the item (CSS value, typically negative)
    </ParamField>

    <ParamField path="orientation" type={`"horizontal" | "vertical"`}>
      The orientation of the sort - Note: line is rendered perpendicular to the sort
    </ParamField>

    <ParamField path="position" type={`"before" | "after"`}>
      The position of the line relative to a target item
    </ParamField>
  </Tab>
</Tabs>
