Composables

useDraggable

Documentation for useDraggable composable.

The useDraggable composable wraps the createDraggable function from AnimeJS.

Arguments

target
DraggableTypes['target'] required
The element(s) to make draggable. Supports CSS selectors, DOM elements, or template refs.
options
DraggableOptions
Configuration for dragging behavior. Highly reactive, supporting Vue refs and getters for most properties.

Example

0%
35%
75%
import { spring } from '#nanime/easings'

const container = useTemplateRef('container')
const draggable = useTemplateRef('draggable')

useDraggable(draggable, {
  container: container,
  releaseEase: spring({
    bounce: 0.65,
    duration: 400,
  }),
  x: {
    snap: (draggable) => {
      const hw = (draggable?.dragArea || [0, 0, 0, 0])[2]
      const results = [0, hw * 0.35, hw * 0.75]
      return results
    },
  },
})
View on GitHub

Return Value

Returns a BufferedProxyReturns<Draggable> object, a reactive proxy around the AnimeJS Draggable instance. Methods stay callable before the instance exists: calls made early are buffered and replayed once it is created.

API

Types

function useDraggable(
  target: DraggableTypes["target"],
  options?: DraggableOptions
): BufferedProxyReturns<Draggable>

See AnimeJS Draggable documentation for more details.

Caveats

  • Property reads can be undefined until the instance exists. The draggable is created after mount, and only once the target resolves. Methods are safe to call before that, but x, y and other properties have nothing to report yet.
  • Never put a CSS transition on transform. useDraggable writes an inline transform every frame, and a transition on that property fights those writes and makes dragging feel laggy. Transition another property, or move the visual change onto a child element.
  • x and y report the element's current position, not how far this drag has moved it. They read whatever property the axis maps to, translateX and translateY by default or the mapTo property if you set one, so they carry over from previous drags instead of starting at 0.
  • Resizing the target schedules a refresh. AnimeJS attaches a ResizeObserver to the element, and any size change trips it, including one made with the standalone CSS scale property. Animate a child element when the target itself does not need to resize.
const draggable = useDraggable('.square')

// callable immediately, buffered until the instance exists
const disable = () => draggable.disable()

For a true drag delta, record x and y in onGrab and subtract:

let origin = { x: 0, y: 0 }

useDraggable(target, {
  onGrab: self => origin = { x: self.x, y: self.y },
  onUpdate: self => moved(self.x - origin.x, self.y - origin.y),
})
Copyright © 2026