draggable

Drag me this text is also draggable
Drag with custom callbacks
this text is not draggable

last pointer: —

svelte<script lang="ts">
  import { draggable } from '$lib/attachments'

  let last_drag: string = $state('')
</script>

<div class="drag-area">
  <!-- Absolute positioned box → default handle is the node itself -->
  <div
    class="drag-box"
    style="position: absolute; left: 1rem; top: 1rem"
    {@attach draggable({
      bounds: `parent`,
      on_drag: (event: PointerEvent) =>
        (last_drag = `${event.clientX}, ${event.clientY}`),
    })}
  >
    Drag me
    <small style="display: block; opacity: 0.7">this text is also draggable</small>
  </div>

  <!-- Second draggable with custom handle and callbacks -->
  <div
    class="drag-box"
    style="position: absolute; left: 12rem; top: 8rem; width: 14rem"
    {@attach draggable({
      handle_selector: `.drag-handle`,
      axis: `x`,
      bounds: `parent`,
      on_drag_start: () => (last_drag = `start`),
      on_drag: (event: PointerEvent) =>
        (last_drag = `${event.clientX}, ${event.clientY}`),
      on_drag_end: () => (last_drag = `end`),
    })}
  >
    <div class="drag-handle">Drag with custom callbacks</div>
    <small style="display: block; opacity: 0.7">this text is not draggable</small>
  </div>
</div>

<p>last pointer: {last_drag || ''}</p>

axis defaults to both; use x or y to lock movement. bounds is sampled when dragging starts and clamps the node to its parent’s or another element’s border box, or to a viewport-coordinate { top, right, bottom, left } rectangle. A node larger than its bounds pins its top-left edge.