useDraggable
Makes any element draggable using Pointer Events. Returns Observable values for position (x$, y$), drag state (isDragging$), and a ready-to-use CSS style string (style$).
Basic drag
Section titled “Basic drag”import { const useRef$: { <T = any>(initialValue: null): Ref$<T | null>; <T = any>(initialValue: T): Ref$<T>; <T = any>(): Ref$<T | null>;}
useRef$ } from "@usels/core";import { const useDraggable: (target: MaybeEventTarget, options?: DeepMaybeObservable<UseDraggableOptions>) => UseDraggableReturn
useDraggable } from "@usels/web";
function function DraggableBox(): JSX.Element
DraggableBox() { const const el$: Ref$<HTMLDivElement | null>
el$ = useRef$<HTMLDivElement>(): Ref$<HTMLDivElement | null> (+2 overloads)
Core (framework-agnostic) version of useRef$.
Creates an observable element ref with opaque wrapping.
- non-null value →
Ref$<T>: current, get(), peek() return T
- null / no arg →
Ref$<T | null>: current, get(), peek() return T | null
Nullability is expressed via the type parameter, mirroring T | null at the call site.
useRef$<interface HTMLDivElement
HTMLDivElement>(); const { const x$: any
Current X position
x$, const y$: any
Current Y position
y$ } = function useDraggable(target: MaybeEventTarget, options?: DeepMaybeObservable<UseDraggableOptions>): UseDraggableReturn
Framework-agnostic draggable Pointer-Events wrapper.
Must be called inside a useScope factory — pointer listeners are
registered via createEventListener and cleaned up automatically when the
scope disposes. Public behavior matches the legacy useDraggable hook.
useDraggable(const el$: Ref$<HTMLDivElement | null>
el$);
return ( <JSX.IntrinsicElements.div: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div RefAttributes<HTMLDivElement>.ref?: Ref<HTMLDivElement> | undefined
Allows getting a ref to the component instance.
Once the component unmounts, React will set ref.current to null
(or call the ref with null if you passed a callback ref).
ref={const el$: Ref$<HTMLDivElement | null>
el$} HTMLAttributes<HTMLDivElement>.style?: CSSProperties | undefined
style={{ StandardLonghandProperties<string | number, string & {}>.position?: Property.Position | undefined
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
Syntax: static | relative | absolute | sticky | fixed
Initial value: static
| Chrome | Firefox | Safari | Edge | IE |
| :----: | :-----: | :----: | :----: | :---: |
| 1 | 1 | 1 | 12 | 4 |
position: "fixed", StandardLonghandProperties<string | number, string & {}>.left?: Property.Left<string | number> | undefined
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
Syntax: auto | <length-percentage> | <anchor()> | <anchor-size()>
Initial value: auto
| Chrome | Firefox | Safari | Edge | IE |
| :----: | :-----: | :----: | :----: | :-----: |
| 1 | 1 | 1 | 12 | 5.5 |
left: `${const x$: any
Current X position
x$.any
get()}px`, StandardLonghandProperties<string | number, string & {}>.top?: Property.Top<string | number> | undefined
This feature is well established and works across many devices and browser versions. It’s been available across browsers since July 2015.
Syntax: auto | <length-percentage> | <anchor()> | <anchor-size()>
Initial value: auto
| Chrome | Firefox | Safari | Edge | IE |
| :----: | :-----: | :----: | :----: | :---: |
| 1 | 1 | 1 | 12 | 5 |
top: `${const y$: any
Current Y position
y$.any
get()}px` }}> Drag me </JSX.IntrinsicElements.div: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>
div> );}import { createRef$ } from "@usels/core";import { createDraggable } from "@usels/web";
function DraggableBox() { "use scope"; const el$ = createRef$<HTMLDivElement>(); const { x$, y$ } = createDraggable(el$);
return ( <div ref={el$} style={{ position: "fixed", left: `${x$.get()}px`, top: `${y$.get()}px` }}> Drag me </div> );}Axis restriction
Section titled “Axis restriction”Restrict movement to a single axis.
const { x$ } = useDraggable(el$, { axis: "x" }); // horizontal onlyconst { y$ } = useDraggable(el$, { axis: "y" }); // vertical onlyWith handle
Section titled “With handle”Attach drag to a specific handle element instead of the whole target.
// @noErrorsimport { useRef$ } from "@usels/core";import { useDraggable } from "@usels/web";
function WithHandle() { const el$ = useRef$<HTMLDivElement>(); const handle$ = useRef$<HTMLDivElement>(); const { style$ } = useDraggable(el$, { handle: handle$ }); // ...}Container boundary
Section titled “Container boundary”Clamp drag position inside a container element.
const { style$ } = useDraggable(el$, { containerElement: container$,});Restrict to viewport
Section titled “Restrict to viewport”const { style$ } = useDraggable(el$, { restrictInView: true,});Callbacks
Section titled “Callbacks”const { isDragging$ } = useDraggable(el$, { onStart: (pos, e) => { if (someCondition) return false; // cancel drag }, onMove: (pos, e) => console.log(pos), onEnd: (pos, e) => savePosition(pos),});Reactive position update
Section titled “Reactive position update”x$ and y$ are writable Observables — setting them directly updates style$ and position$.
const { x$, y$, style$, position$ } = useDraggable(el$);x$.set(100);y$.set(200);// style$.get() === 'left: 100px; top: 200px;'Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
target | MaybeEventTarget | - Element to make draggable (Ref$, Observable<Element|null>, raw Element, etc.). |
options | UseDraggableOptions (optional) | - Configuration (supports DeepMaybeObservable — each field may be an Observable). |
UseDraggableOptions
Section titled “UseDraggableOptions”Returns
Section titled “Returns”UseDraggableReturn
| Name | Type | Description |
|---|---|---|
x$ | ObservablePrimitive<number> | Current X position |
y$ | ObservablePrimitive<number> | Current Y position |
position$ | Observable<Position> | Current position as { x, y } |
isDragging$ | ObservableBoolean<boolean> | Whether currently dragging |
style$ | ObservablePrimitive<string> | CSS position string: “left: Xpx; top: Ypx;“ |