Components

Draggable

Source
Headless 2D pan-gesture primitive with axis locking, bounds, momentum, and reset.

Overview

Draggable is a headless @vyui/core primitive that turns its child into a draggable element via a main-thread pan gesture. It is the building block behind Sortable and other drag-driven interactions, and tracks the finger natively for smooth motion.

This is a vyui-original @vyui/core primitive — a 2D pan gesture over Lynx main-thread touch events. Behavior only, no styles.

Usage

<script setup lang="ts">
import { Draggable } from '@vyui/core'

function onEnd(payload) {
  console.log('settled at', payload.x, payload.y)
}
</script>

<template>
  <Draggable
    axis="both"
    :bounds="{ left: -120, right: 120, top: -80, bottom: 80 }"
    reset-on-end
    @drag-end="onEnd"
  >
    <view class="size-16 rounded-xl bg-primary" />
  </Draggable>
</template>

Features and behavior

  • axis locks dragging to 'x', 'y', or 'both' (free 2D pan).
  • bounds constrains the drag in px relative to the origin; an omitted side is unbounded.
  • resetOnEnd animates back to (0, 0) on release (duration tunes the animation).
  • momentum carries release velocity into a decelerating coast (clamped to bounds); ignored when resetOnEnd is set. momentumDecel controls how quickly the fling stops.
  • emitMove opts into a drag-move event on every touchmove; drag-start and drag-end always fire.

API

Props

PropDefaultType
axis"both"DraggableAxis | undefined

Lock drag to a single axis. `'both'` allows free 2D pan.

boundsDraggableBounds | undefined

Bounds in px relative to the drag origin. Omitted side = unbounded.

disabledfalseboolean | undefined

Disable interaction.

duration220number | undefined

Reset animation duration in ms. Only used when `resetOnEnd` is `true`.

emitMovefalseboolean | undefined

Emit `drag-move` on every touchmove. Off by default.

momentumfalseboolean | undefined

Carry release velocity into a momentum coast: a flick keeps gliding and decelerates to rest (clamped to `bounds`) instead of stopping dead at the finger. Ignored when `resetOnEnd` is `true` (reset wins). Off by default.

momentumDecel5number | undefined

Deceleration rate for `momentum`. Higher = shorter fling. Projected coast distance is `velocity / decel`.

resetOnEndfalseboolean | undefined

Animate back to `(0, 0)` on release.

Emits

EventPayload
dragStart[DraggablePosition]
dragMove[DragMovePayload]
dragEnd[DragEndPayload]

The drag-move payload adds dx / dy (delta from touchstart); drag-end additionally carries vx / vy release velocity in px/s.

Accessibility

  • Pointer dragging has no keyboard equivalent — provide an alternative control path for keyboard and assistive-tech users where the interaction is essential.

Platform notes

  • The gesture is implemented with main-thread (MTS) touch worklets, so tracking stays smooth independent of the background thread.
  • Sortable — reorderable lists built on this primitive.
  • Swiper — paged horizontal swiping.
  • Sheet — snap/drag bottom sheet.