Integrations
elements
lifecycle
browser
- useAudio
- useBattery
- useBluetooth
- useBreakpoints
- useBroadcastChannel
- useBrowserLocation
- useClipboard
- useCopy
- useCssVar
- useDeviceList
- useDisplayMedia
- useDocumentEvent
- useDocumentTitle
- useDocumentVisibility
- useEventListener
- useEventSource
- useEyeDropper
- useFavicon
- useFileSystemAccess
- useFps
- useFullscreen
- useGamepad
- useGeolocation
- useMeasure
- useMediaControls
- useMediaQuery
- useMediaStream
- useMemory
- useNetwork
- useNotification
- useObjectUrl
- useOnline
- useOtpCredential
- usePermission
- usePictureInPicture
- usePointerLock
- usePostMessage
- useRaf
- useShare
- useSpeechRecognition
- useSpeechSynthesis
- useSticky
- useVibrate
- useVirtualKeyboard
- useWakeLock
- useWebSocket
utilities
state
- useBoolean
- useControllableState
- useCookie
- useCookies
- useCounter
- useCycleList
- useDefault
- useDisclosure
- useField
- useForm
- useHash
- useList
- useLocalStorage
- useMap
- useMask
- useMergedRef
- useObject
- useOffsetPagination
- useQueue
- useRafState
- useRefState
- useSessionStorage
- useSet
- useStateHistory
- useStep
- useStorage
- useToggle
- useUrlSearchParam
- useUrlSearchParams
- useValidatedState
- useWizard
user
sensors
- useDeviceMotion
- useDeviceOrientation
- useHotkeys
- useIdle
- useInfiniteScroll
- useIntersectionObserver
- useKeyboard
- useKeyPress
- useKeysPressed
- useMouse
- useMutationObserver
- useOrientation
- usePageLeave
- useParallax
- usePerformanceObserver
- useResizeObserver
- useScroll
- useScrollIntoView
- useScrollTo
- useSwipe
- useTextSelection
- useVisibility
- useWindowEvent
- useWindowFocus
- useWindowScroll
- useWindowSize
Project Atlas
Design reviewIn progress
Finalize the dashboard mockups and hand off specs to engineering before Friday.
import { useDraggable } from '@siberiacancode/reactuse';
import { GripVerticalIcon } from 'lucide-react';
import { useRef } from 'react';
const Demo = () => {
const cardRef = useRef<HTMLDivElement>(null);
useDraggable(cardRef, {
onStart: ({ event }) => {
const target = event.target as HTMLElement;
if (!target.closest('[data-drag-handle]')) return false;
if (cardRef.current) cardRef.current.style.transition = 'none';
},
onMove: ({ delta }) => {
if (cardRef.current)
cardRef.current.style.transform = `translate(${delta.x}px, ${delta.y}px)`;
},
onEnd: () => {
if (cardRef.current) {
cardRef.current.style.transition = 'transform 0.35s cubic-bezier(0.22, 1, 0.36, 1)';
cardRef.current.style.transform = 'translate(0px, 0px)';
}
}
});
return (
<section className='relative'>
<div ref={cardRef} className='w-64 select-none' style={{ transform: 'translate(0px, 0px)' }}>
<div className='bg-card text-card-foreground border-border rounded-xl border shadow-md'>
<div
data-drag-handle
className='border-border bg-muted/50 flex cursor-grab items-center gap-2 rounded-t-xl border-b px-3 py-2 active:cursor-grabbing'
>
<GripVerticalIcon className='text-muted-foreground size-4' />
<span className='text-sm font-medium'>Project Atlas</span>
</div>
<div className='flex flex-col gap-3 p-4'>
<div className='flex items-center justify-between'>
<span className='text-sm font-medium'>Design review</span>
<span className='border-border rounded-full border px-2 py-0.5 text-xs font-medium'>
In progress
</span>
</div>
<p className='text-muted-foreground text-sm'>
Finalize the dashboard mockups and hand off specs to engineering before Friday.
</p>
</div>
</div>
</div>
</section>
);
};
export default Demo;
Installation
pnpm add @siberiacancode/reactuseUsage
const { snapshot, watch, dragging, set } = useDraggable(ref);
// or
const { ref, snapshot, watch, dragging, set } = useDraggable<HTMLDivElement>();Type Declarations
import type { HookTarget } from '@/utils/helpers';
import type { StateRef } from '../useRefState/useRefState';
export interface UseDraggablePosition {
/** The x coordinate */
x: number;
/** The y coordinate */
y: number;
}
export interface UseDraggableEvent {
/** The delta offset from the drag start point (suitable for transform: translate) */
delta: UseDraggablePosition;
/** The original pointer event */
event: PointerEvent;
/** The absolute position (suitable for left/top with fixed positioning) */
position: UseDraggablePosition;
}
export interface UseDraggableOptions {
/** The axis to drag on */
axis?: 'both' | 'x' | 'y';
/** The enabled state of the draggable */
enabled?: boolean;
/** The initial position of the element */
initialValue?: UseDraggablePosition;
/** The callback when dragging ends */
onEnd?: (params: UseDraggableEvent) => void;
/** The callback during dragging */
onMove?: (params: UseDraggableEvent) => void;
/** The callback when dragging starts. Return `false` to prevent dragging */
onStart?: (params: UseDraggableEvent) => false | void;
}
export interface UseDraggableReturn {
/** Whether the element is currently being dragged */
dragging: boolean;
/** The latest position snapshot */
snapshot: UseDraggablePosition;
/** Function to set the position programmatically */
set: (position: UseDraggablePosition) => void;
/** Function to enable subscriptions and rerender on next updates */
watch: () => UseDraggablePosition;
}
export interface UseDraggable {
(target: HookTarget, options?: UseDraggableOptions): UseDraggableReturn;
<Target extends Element>(
options?: UseDraggableOptions,
target?: never
): UseDraggableReturn & {
ref: StateRef<Target>;
};
}API
Parameters
| Name | Type | Default | Note |
|---|---|---|---|
| target | HookTarget | - | The target element to make draggable |
| options.enabled | boolean | true | The enabled state of the draggable |
| options.axis | 'x' | 'y' | 'both' | 'both' | The axis to drag on |
| options.initialValue | UseDraggablePosition | - | The initial position of the element |
Returns
UseDraggableReturnParameters
| Name | Type | Default | Note |
|---|---|---|---|
| options.enabled | boolean | true | The enabled state of the draggable |
| options.axis | 'x' | 'y' | 'both' | 'both' | The axis to drag on |
| options.initialValue | UseDraggablePosition | - | The initial position of the element |
Returns
UseDraggableReturn & { ref: StateRef<Target> }Contributors
ddebabin
Last updated on