Docs
useDraggable

A hook to manage draggable elements with useDraggable.

Loading...

Installation

pnpm dlx shadcn@latest add https://usekit.kiron.dev/k/use-draggable

Usage

"use client"
 
import { useDraggable } from "@/hooks/use-draggable"
 
export function Component() {
  const { ref, isDragging } = useDraggable<HTMLDivElement>()
 
  return (
    <div
      ref={ref}
      style={{
        width: "200px",
        height: "200px",
        backgroundColor: isDragging ? "lightblue" : "lightcoral",
        cursor: "grab",
        userSelect: "none", // Prevent text selection while dragging
      }}
    >
      Drag me!
    </div>
  )
}

Examples

Example 1: Basic Draggable Div

This example shows how to make a simple div draggable.

import { useDraggable } from "@/hooks/use-draggable"
 
const DraggableDiv = () => {
  const { ref, isDragging } = useDraggable<HTMLDivElement>()
 
  return (
    <div
      ref={ref}
      style={{
        width: "200px",
        height: "200px",
        backgroundColor: isDragging ? "lightblue" : "lightcoral",
        cursor: "grab",
        userSelect: "none", // Prevent text selection while dragging
      }}
    >
      Drag me!
    </div>
  )
}
 
export default DraggableDiv

Example 2: Draggable with Conditional Logic

This example adds a condition to allow dragging only if the element is not disabled.

import * as React from "react"
 
import { useDraggable } from "@/hooks/use-draggable"
 
const ConditionalDraggable = () => {
  const [isDisabled, setIsDisabled] = React.useState(false)
  const { ref, isDragging } = useDraggable<HTMLDivElement>({
    canDrag: (element) => !isDisabled, // Only allow dragging if not disabled
  })
 
  return (
    <div>
      <div
        ref={ref}
        style={{
          width: "200px",
          height: "200px",
          backgroundColor: isDragging ? "lightgreen" : "lightpink",
          cursor: isDisabled ? "not-allowed" : "grab",
          userSelect: "none",
        }}
      >
        {isDisabled ? "Disabled" : "Drag me!"}
      </div>
      <button onClick={() => setIsDisabled(!isDisabled)}>
        {isDisabled ? "Enable Dragging" : "Disable Dragging"}
      </button>
    </div>
  )
}
 
export default ConditionalDraggable

Example 3: Draggable Image

This example makes an image draggable.

import { useDraggable } from "@/hooks/use-draggable"
 
const DraggableImage = () => {
  const { ref, isDragging } = useDraggable<HTMLImageElement>()
 
  return (
    <img
      ref={ref}
      src="https://via.placeholder.com/200"
      alt="Draggable"
      style={{
        cursor: "grab",
        border: isDragging ? "2px solid blue" : "2px solid transparent",
        userSelect: "none",
      }}
    />
  )
}
 
export default DraggableImage

Example 4: Draggable with Boundaries

This example restricts dragging within a container.

import * as React from "react"
 
import { useDraggable } from "@/hooks/use-draggable"
 
const BoundedDraggable = () => {
  const containerRef = React.useRef<HTMLDivElement>(null)
  const { ref, isDragging } = useDraggable<HTMLDivElement>({
    canDrag: (element) => {
      // Ensure the element stays within the container
      const container = containerRef.current
      if (!container) return true
 
      const containerRect = container.getBoundingClientRect()
      const elementRect = element.getBoundingClientRect()
 
      return (
        elementRect.left >= containerRect.left &&
        elementRect.right <= containerRect.right &&
        elementRect.top >= containerRect.top &&
        elementRect.bottom <= containerRect.bottom
      )
    },
  })
 
  return (
    <div
      ref={containerRef}
      style={{
        position: "relative",
        width: "500px",
        height: "500px",
        border: "2px solid black",
        overflow: "hidden",
      }}
    >
      <div
        ref={ref}
        style={{
          width: "100px",
          height: "100px",
          backgroundColor: isDragging ? "lightyellow" : "lightseagreen",
          cursor: "grab",
          userSelect: "none",
        }}
      >
        Drag me!
      </div>
    </div>
  )
}
 
export default BoundedDraggable

Example 5: Draggable List Items

This example makes each item in a list draggable.

import { useDraggable } from "@/hooks/use-draggable"
 
const DraggableList = () => {
  const items = ["Item 1", "Item 2", "Item 3", "Item 4"]
 
  return (
    <div>
      {items.map((item, index) => {
        const { ref, isDragging } = useDraggable<HTMLLIElement>()
        return (
          <li
            key={index}
            ref={ref}
            style={{
              padding: "10px",
              margin: "5px",
              backgroundColor: isDragging ? "lightgray" : "white",
              cursor: "grab",
              userSelect: "none",
              border: "1px solid #ccc",
              listStyle: "none",
            }}
          >
            {item}
          </li>
        )
      })}
    </div>
  )
}
 
export default DraggableList

Example 6: Draggable with Snap-to-Grid

This example snaps the draggable element to a grid.

import { useDraggable } from "@/hooks/use-draggable"
 
const SnapToGridDraggable = () => {
  const { ref, isDragging } = useDraggable<HTMLDivElement>({
    canDrag: (element) => {
      // Snap to grid logic
      const gridSize = 50
      const rect = element.getBoundingClientRect()
      const snappedX = Math.round(rect.left / gridSize) * gridSize
      const snappedY = Math.round(rect.top / gridSize) * gridSize
      element.style.transform = `translate(${snappedX}px, ${snappedY}px)`
      return true
    },
  })
 
  return (
    <div
      ref={ref}
      style={{
        width: "100px",
        height: "100px",
        backgroundColor: isDragging ? "lightcyan" : "lightgoldenrodyellow",
        cursor: "grab",
        userSelect: "none",
      }}
    >
      Snap to Grid
    </div>
  )
}
 
export default SnapToGridDraggable

API Reference

Parameters

NameTypeDescriptionDefault ValueOptional
canDragfunctionA function that determines whether the element can be dragged.() => trueYes

Return Values

NameTypeDescription
refRefObject<T>A React ref object to attach to the draggable element.
isDraggingbooleanA boolean value indicating whether the element is currently being dragged.