---
title: useDraggable
description: Make an element draggable between viewport corners with snapping, persistence, and animation support.
---
`useDraggable()` provides drag-to-corner functionality. Used internally by `ConsentDialogTrigger`, this hook lets you build custom draggable elements that snap to viewport corners.

```tsx
import { useDraggable } from '@c15t/nextjs';

function DraggableButton() {
  const { corner, isDragging, handlers, dragStyle } = useDraggable({
    defaultPosition: 'bottom-right',
    persistPosition: true,
  });

  return (
    <button
      {...handlers}
      style={{
        ...dragStyle,
        position: 'fixed',
        // Position based on corner
        ...(corner.includes('bottom') ? { bottom: 16 } : { top: 16 }),
        ...(corner.includes('right') ? { right: 16 } : { left: 16 }),
      }}
    >
      {isDragging ? 'Dragging...' : 'Drag me'}
    </button>
  );
}
```

## Options

| Option             | Type                                 | Default          | Description                   |
| ------------------ | ------------------------------------ | ---------------- | ----------------------------- |
| `defaultPosition`  | `CornerPosition`                     | `'bottom-right'` | Initial corner position       |
| `persistPosition`  | `boolean`                            | `true`           | Save position to localStorage |
| `onPositionChange` | `(position: CornerPosition) => void` | -                | Callback on position change   |

## Return Value

| Property     | Type             | Description                                        |               |                 |                  |
| ------------ | ---------------- | -------------------------------------------------- | ------------- | --------------- | ---------------- |
| `corner`     | `CornerPosition` | Current corner: `'top-left'`                       | `'top-right'` | `'bottom-left'` | `'bottom-right'` |
| `isDragging` | `boolean`        | Whether the element is being dragged               |               |                 |                  |
| `isSnapping` | `boolean`        | Whether the element is animating to a new corner   |               |                 |                  |
| `wasDragged` | `() => boolean`  | Whether the last interaction was a drag (vs click) |               |                 |                  |
| `handlers`   | `object`         | Pointer event handlers to spread onto the element  |               |                 |                  |
| `dragStyle`  | `CSSProperties`  | Transform style for drag offset                    |               |                 |                  |

## Behavior

* Drag starts on pointer down (left click / single touch)
* Movement threshold of 5px distinguishes drag from click
* On pointer up, element snaps to the nearest corner based on drag direction and velocity
* Position persists to localStorage by default
