@thepaulin/d_ui
v0.1.2
Published
React drag-and-drop library with position persistence for any JS metaframework
Maintainers
Readme
@thepaulin/d_u
A lightweight React drag-and-drop library with position persistence. Built for any JS metaframework (Next.js, Remix, Gatsby, etc.).
npm install @thepaulin/d_uUsage
import { DraggableUI, Draggable } from '@thepaulin/d_u';
function App() {
return (
<DraggableUI>
<Draggable id="card-1" defaultPosition={{ x: 100, y: 200 }}>
<div>Drag me</div>
</Draggable>
</DraggableUI>
);
}Persistence and drag context are configured via DraggableUI. Drop-in Draggable makes any child element movable.
Features
- Position persistence — positions saved to
localStorageby default; survives page reloads - Custom storage — supply your own
StorageAdapterfor server/DB-backed persistence - Two positioning modes —
transform(no layout shift) orabsolute - Axis constraint — restrict dragging to
x,y, orboth - Grid snapping — snap to any
[column, row]grid - Drag handles — restrict drag start to a specific handle element
- Full event callbacks —
onDragStart,onDrag,onDragEnd - Headless hook —
useDraggablefor completely custom rendering - Imperative control —
usePositionto read or update positions outside of drag - SSR-safe — no
windowreferences on the server - Zero runtime deps — only peer dependency on React 16.8+
API
<DraggableUI>
Root provider. Must wrap all Draggable instances.
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| storageKey | string | 'default' | Key for persisting positions |
| storageAdapter | StorageAdapter | localStorage adapter | Custom persistence backend |
| positioningMode | 'transform' \| 'absolute' | 'transform' | CSS strategy for positioning |
| className | string | — | Class for the wrapper element |
| style | CSSProperties | — | Inline styles for the wrapper |
| as | ElementType | 'div' | Wrapper element tag |
<Draggable>
Makes its single child element draggable.
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| id | string | required | Unique identifier |
| defaultPosition | { x: number, y: number } | { x: 0, y: 0 } | Initial position |
| disabled | boolean | false | Disables dragging |
| axis | 'both' \| 'x' \| 'y' | 'both' | Restrict movement axis |
| grid | [number, number] | — | Snap grid [column, row] |
| zIndex | number | — | Z-index while dragging (via style) |
| handle | RefObject<HTMLElement> | — | Element that must be clicked to drag |
| onDragStart | (event) => void | — | Called on drag start |
| onDrag | (event) => void | — | Called on each drag move |
| onDragEnd | (event) => void | — | Called on drag end |
useDraggable(options)
Headless hook — returns { ref, style, onPointerDown, attributes } for fully custom rendering.
usePosition(id, defaultPosition?)
Read and update a draggable's position imperatively. Returns { x, y, setPosition, resetPosition }.
useDragContext()
Access the nearest DraggableUI context. Throws if called outside a provider.
Types
| Export | Description |
|--------|-------------|
| Position | { x: number, y: number } |
| StorageAdapter | { getItem, setItem, removeItem } |
| PositioningMode | 'transform' \| 'absolute' |
| DragStartEvent | Event payload on drag start |
| DragMoveEvent | Event payload during drag |
| DragEndEvent | Event payload on drag end |
Developing
git clone https://github.com/thepaulin/d_ui.git
cd d_ui
npm installScripts
| Command | Description |
|---------|-------------|
| npm run dev | Watch mode rebuild |
| npm run build | Production build via tsup |
| npm test | Run test suite (Vitest) |
| npm run test:watch | Watch mode tests |
| npm run test:coverage | Test coverage report |
| npm run typecheck | TypeScript type check |
Project structure
src/
components/ — DraggableUI, Draggable
context/ — DragContext provider
hooks/ — useDraggable, usePosition, useDragContext
utils/ — storage, coordinates, guards
types/ — TypeScript interfaces
constants.ts — shared constantsContributing
- Fork the repo and create a feature branch.
- Run
npm installandnpm run devto start the build watcher. - Write or update tests under
src/**/__tests__/. - Run
npm testandnpm run typecheck— all must pass. - Open a pull request.
The library aims to be minimal. New features should justify their weight. When in doubt, open an issue first to discuss.
