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

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

> [!NOTE]
>
> For development, import `Dnd` from
> `@servicetitan/anvil2`. For design, find it in the
> [Anvil2 file](https://www.figma.com/design/xaNQsvRKczoxu7pj0M6QT8/Anvil2-v3?node-id=2625-10080).

## Anatomy

Dnd consists of three primary components that work together to create drag and drop interfaces.

![Dnd
anatomy](https://mintcdn.com/servicetitan/gLoz1MFH6ICVCCBs/images/docs/web/components/dnd/dnd_anatomy.png?fit=max\&auto=format\&n=gLoz1MFH6ICVCCBs\&q=85\&s=c9e2af9e8d7c30bb40de98b164d2cc50)

1. **Drop Zone** - Active but not over
2. **Drop Zone** - Over and valid
3. **Drop Zone** - Over and invalid
4. **Sort Line**
5. **Handle**

## Options

Dnd supports the following configurations to accommodate various drag and drop scenarios.

### Drop Zone

dnd-sort-drop-zone

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/dnd-sort-drop-zone?file=src/App.tsx)

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

function App() {
  return (
    <Flex gap={4}>
      <Dnd.Zone style={{ width: "25%" }} className="p-3">
        Resting Drop Zone
      </Dnd.Zone>
      <Dnd.Zone isDragging style={{ width: "25%" }} className="p-3">
        Visible Drop Zone while dragging
      </Dnd.Zone>
      <Dnd.Zone
        isDragging
        isOver
        isValid
        style={{ width: "25%" }}
        className="p-3"
      >
        Valid Drop Zone, user is over the Drop Zone
      </Dnd.Zone>
      <Dnd.Zone isDragging isOver style={{ width: "25%" }} className="p-3">
        Invalid drop zone, user is over the Drop Zone
      </Dnd.Zone>
    </Flex>
  );
}

export default App;
```

Drop Zone displays different visual states based on drag conditions:

* **Active but not over** - Shows a dashed border when an item is being dragged but not over the drop zone
* **Over and valid** - Shows a solid border with success styling when a valid item is over the drop zone
* **Over and invalid** - Shows a dashed border with danger styling when an invalid item is over the drop zone

### Handle

dnd-handle

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/dnd-handle?file=src/App.tsx)

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

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

export default App;
```

The Handle displays an icon to indicate that an item is draggable. It can be configured to be decorative or interactive, depending on the use case.

### Sort Line

dnd-sort-line-vertical

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/dnd-sort-line-vertical?file=src/App.tsx)

```tsx lines 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;
```

dnd-sort-line-horizontal

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/dnd-sort-line-horizontal?file=src/App.tsx)

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

function App() {
  return (
    <div style={{ height: "40px", position: "relative" }}>
      <Dnd.SortLine orientation="horizontal" position="before" offset="0" />
    </div>
  );
}

export default App;
```

Sort Line indicates where an item will be dropped in a sortable list. The line width is based on its nearest relatively positioned ancestor. Use Sort Line for one-dimensional sorting in vertical or horizontal lists. Sort Line is not suitable for two-dimensional sorting such as grids.

## Usage Guidelines

Dnd is a collection of UI components, rather than a complete drag and drop solution. Additional work is needed in design to make it a complete drag and drop solution.

| Standard | Requirement |
| - | - |
| DoCustom drag and drop interactions | Custom drag and drop interactions not covered by DndSort |
| DoSpecific visual feedback | Specific visual feedback for drag states |
| DoIntegrating external libraries | Integration with external drag and drop libraries |
| DoFine-grained control | Fine-grained control over drag and drop behavior |
| Don'tBasic sorting or grouping needs | Basic sorting or grouping needs can be met by [Dnd Sort](https://anvil.servicetitan.com/docs/components/dnd-sort/web.md) |
| Don'tA complete drag and drop solution | You need a complete drag and drop solution without implementing interactions yourself |

### Alternatives

#### Dnd vs DndSort

DndSort is a pre-built composition that uses all Dnd components to cover many basic cases including sorting a list, arranging items into groups, or both. Use DndSort when it meets your needs. Use Dnd when you require custom drag and drop behavior beyond what DndSort provides.

#### Provide alternatives to Drag and Drop

While Dnd is keyboard navigable, alternative interactions should be provided for users who cannot or do not want to use drag and drop.

## Content

Content within Dnd components should clearly communicate drag and drop capabilities and provide appropriate visual feedback.

* Drop Zone content should indicate what can be dropped in the area
* Handle and Handle Button should be clearly visible and indicate draggability
* Sort Line should appear at the precise drop location to guide users

## Keyboard Interaction

Users can navigate Dnd components using standard keyboard controls.

Dnd components provide visual styling only and do not implement keyboard interactions. Implement keyboard navigation using your chosen drag and drop library or custom keyboard handlers to ensure accessibility.

## Code

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

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

dnd-zone

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/dnd-zone?file=src/App.tsx)

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

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

export default App;
```

### Handle

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

dnd-handle

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/dnd-handle?file=src/App.tsx)

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

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

export default App;
```

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

dnd-handlebutton

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/dnd-handlebutton?file=src/App.tsx)

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

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

export default App;
```

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

dnd-sortline

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/dnd-sortline?file=src/App.tsx)

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

### 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](https://anvil.servicetitan.com/docs/components/dnd-sort/code).

## Best Practices

### Draggables with interactivity

dnd-do-interactive

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/dnd-do-interactive?file=src/App.tsx)

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

> [!TIP]
>
> **Do**

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

dnd-dont-interactive

[StackBlitz demo](https://stackblitz.com/github/servicetitan/anvil2-docs-live-code/tree/main/examples/dnd-dont-interactive?file=src/App.tsx)

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

> [!CAUTION]
>
> **Don't**

If your draggable item has interactive elements, don't nest interactive elements.

**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

**isDragging** `boolean` *required*

Whether an item is currently being dragged.

**isOver** `boolean` *required*

Whether an item is currently being dragged over the zone.

**isValid** `boolean` *required*

Whether the current drag operation is valid for this zone.

**children** `ReactNode`

Child elements to render inside the zone.

**className** `string`

Optional CSS class name to apply to the zone.

**el** `ElementType` (default: div)

The HTML element type to render.

All props for the specified element type are also supported.

**Dnd.Handle Props**

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

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

## `Dnd.Handle` Props

**className** `string`

Optional CSS class name to apply to the handle

**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`](https://anvil.servicetitan.com/docs/components/button/design#anatomy) props.

**className** `string`

Optional CSS class name to apply to the button

**isActive** `boolean` (default: false)

Whether the handle is currently being dragged

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

**offset** `string`

The offset of the line from the item (CSS value, typically negative)

**orientation** `"horizontal" | "vertical"`

The orientation of the sort - Note: line is rendered perpendicular to the sort

**position** `"before" | "after"`

The position of the line relative to a target item


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.