Fluxo UIFluxo UIv0.4.93

Moveable

A drag wrapper for any element. Position anything freely on the page with mouse, touch, or keyboard — with bounds, axis lock, grid snapping, drag handles, and optional position persistence.

Basic Usage

Wrap any element. Drag with the mouse / touch, or focus the element and press arrow keys.

Basic Drag

Click and drag anywhere on the wrapped element. Tab to focus, then use arrow keys to move.

Drag me anywhere
Position: x = 0, y = 0
import { Moveable } from 'fluxo-ui';

<Moveable defaultPosition={{ x: 0, y: 0 }} bounds="parent">
  <div className="p-4 bg-bg-subtle border rounded">Drag me</div>
</Moveable>

Drag Handle & Axis Lock

Use handleSelector to restrict drag start to a header, and axis to lock to x or y.

Drag Handle & Axis Lock

Use handleSelector to restrict drag start to a header, cancelSelector to exclude inner buttons/inputs, and axis to lock to one direction.

⋮⋮ Drag here

Body text is NOT a drag handle.

axis: x only ↔
axis: y only ↕
<Moveable
  handleSelector=".my-handle"
  cancelSelector="button"
  axis="x"
  bounds="parent"
>
  <div className="card">
    <div className="my-handle">::: drag here :::</div>
    <p>Body — not draggable.</p>
    <button>Action — clicks pass through</button>
  </div>
</Moveable>

Grid Snap

Use grid={[stepX, stepY]} for crisp, aligned positioning.

Grid Snap & Bounds

Drag snaps to a 40-pixel grid while staying inside the parent.

Snap
<Moveable
  defaultPosition={{ x: 0, y: 0 }}
  bounds="parent"
  grid={[40, 40]}
  snapToGrid
>
  <div>Snaps to 40px grid</div>
</Moveable>

Compose with Resizable

Wrap a Resizable inside a Moveable to build a floating, sizeable panel — the same primitives the DashboardLayout uses.

Compose with Resizable

Wrap a Resizable inside a Moveable to get a floating panel that can be both dragged and resized — the same primitives the DashboardLayout uses.

⋮⋮ Floating Panel
Drag the title bar to move. Drag the bottom-right corner to resize.
// Compose Moveable + Resizable for a floating, sizeable widget
<Moveable defaultPosition={{ x: 24, y: 24 }} bounds="parent" handleSelector=".eui-demo-handle">
  <Resizable defaultWidth={260} defaultHeight={160} minWidth={140} minHeight={100}>
    <div className="card">
      <div className="eui-demo-handle">Drag</div>
      <p>Resizable + movable</p>
    </div>
  </Resizable>
</Moveable>

Import

import { Moveable } from 'fluxo-ui';
import type { MoveableProps, MoveablePosition } from 'fluxo-ui';

Moveable Props

childrenreq
React.ReactNode

Element(s) wrapped by the movable container.

defaultPosition
{ x: number; y: number }"{ x: 0, y: 0 }"

Initial position (uncontrolled). Translated relative to the wrapper's CSS origin.

position
{ x: number; y: number }

Controlled position. Provide together with `onPositionChange`.

onPositionChange
(pos: { x: number; y: number }) => void

Fires on every position change (mouse, touch, keyboard).

onMoveStart
(event: MoveableStartEvent) => void

Fires when a drag/keypress sequence begins.

onMove
(event: MoveableMoveEvent) => void

Fires continuously while moving.

onMoveEnd
(event: MoveableEndEvent) => void

Fires when the move gesture ends.

axis
'both' | 'x' | 'y'"'both'"

Restrict movement to a single axis.

bounds
'parent' | 'window' | 'none' | { left, top, right, bottom }"'none'"

Confine movement. Numeric bounds are translate-space offsets (not CSS coords).

grid
[number, number]

Snap position to a [stepX, stepY] grid (requires `snapToGrid`).

disabled
boolean"false"

Disable all interaction.

handleSelector
string

CSS selector for an inner handle. If set, drags only start when the pointer is on a matching element.

cancelSelector
string

CSS selector for inner elements that should NOT initiate drag (buttons, inputs, etc.).

cursor
string"'move'"

Cursor used while dragging.

snapToGrid
boolean"true"

Apply the `grid` snap. Ignored if `grid` is unset.

keyboardStep
number"8"

Pixels per arrow-key press when the wrapper is focused.

keyboardBigStep
number"32"

Pixels per Shift+arrow press.

elevateOnDrag
boolean"true"

Add `z-index` + shadow while dragging.

rememberLastPosition
boolean"false"

Persist the last position to `localStorage` (requires `storageKey`).

storageKey
string

localStorage key for `rememberLastPosition`.

className
string

Class name applied to the outer wrapper.

style
React.CSSProperties

Inline styles for the wrapper.

ariaLabel
string"'Movable element'"

Accessible name for the draggable wrapper.

Features

Wraps Any Element

Turn any React node into a draggable element with a single wrapper.

Bounds Aware

Keep movement inside the parent, the window, or a custom rect.

Drag Handle Support

Restrict drag start to a specific child via handleSelector.

Axis Lock

Restrict movement to the x-axis or y-axis.

Grid Snap

Provide [stepX, stepY] to snap drag to a perfectly aligned grid.

Keyboard Movement

Focus + arrow keys to move with the keyboard (Shift for bigger steps).

Position Persistence

Set rememberLastPosition + storageKey to restore position across sessions.

Composes Cleanly

Nest Resizable inside Moveable to build floating, resizable panels.