Skip to main content
On this pageFunctions

Ui/DragAndDrop

Functions

draggable

functionsource
/** Returns attributes the parent attaches to a draggable element. Handles pointer-down, keyboard activation, and ARIA. */
<ParentMessage>(config: DraggableConfig<ParentMessage>): readonly Array<Attribute<ParentMessage>>

droppable

functionsource
/** Returns attributes the parent attaches to a droppable container element. */
<ParentMessage>(
  containerId: string,
  label?: string
): readonly Array<Attribute<ParentMessage>>

ghostStyle

functionsource
/** Returns positioning styles for the ghost element, or None when not dragging with a pointer. */
(model: DragAndDrop.Model): Option<Record<string, string>>

init

functionsource
/** Creates an initial drag-and-drop model. Starts in the Idle state with Vertical orientation and 5px activation threshold by default. */
(config: InitConfig): DragAndDrop.Model

isDragging

functionsource
/** Returns true when the component is actively dragging (pointer or keyboard). */
(__namedParameters: DragAndDrop.Model): boolean

maybeDraggedItemId

functionsource
/** Returns the ID of the item currently being dragged or pending, if any. */
(model: DragAndDrop.Model): Option<string>

maybeDropTarget

functionsource
/** Returns the current drop target, if any. Populated during pointer drag (from collision detection) and keyboard drag (from resolved position). */
(model: DragAndDrop.Model): Option<{
  containerId: string
  index: number
}>

sortable

functionsource
/** Returns attributes the parent attaches to a sortable item element. Typically combined with `draggable`. */
<ParentMessage>(itemId: string): readonly Array<Attribute<ParentMessage>>

update

functionsource

Types

DraggableConfig

typesource
/** Configuration for creating draggable attributes with `draggable`. */
type DraggableConfig = Readonly<{
  containerId: string
  index: number
  itemId: string
  model: Model
  toParentMessage: (message: DraggableMessage) => ParentMessage
}>

DraggableMessage

typesource
/** Messages the draggable view helper can dispatch. */
type DraggableMessage = typeof PressedDraggable.Type | typeof ActivatedKeyboardDrag.Type

InitConfig

typesource
type InitConfig = Readonly<{
  activationThreshold: number
  id: string
  orientation: "Horizontal" | "Vertical"
}>

Constants

ActivatedKeyboardDrag

constsource
/** The user activated keyboard drag with Space or Enter on a focused draggable. */
const ActivatedKeyboardDrag: CallableTaggedStruct<"ActivatedKeyboardDrag", {
  containerId: String
  index: Number
  itemId: String
}>

Cancelled

constsource
/** Emitted when a drag is cancelled via Escape or pointer release without a drop target. */
const Cancelled: CallableTaggedStruct<"Cancelled", {}>

CancelledDrag

constsource
/** Escape was pressed during a drag. */
const CancelledDrag: CallableTaggedStruct<"CancelledDrag", {}>

CompletedAutoScroll

constsource
/** An animation frame fired during auto-scroll. */
const CompletedAutoScroll: CallableTaggedStruct<"CompletedAutoScroll", {}>

CompletedFocusItem

constsource
/** The FocusItem Command completed. */
const CompletedFocusItem: CallableTaggedStruct<"CompletedFocusItem", {}>

ConfirmedKeyboardDrop

constsource
/** The user confirmed a keyboard drop with Space or Enter. */
const ConfirmedKeyboardDrop: CallableTaggedStruct<"ConfirmedKeyboardDrop", {}>

FocusItem

constsource
/** Focuses a draggable item by ID after keyboard drop or cancel. */
const FocusItem: CommandDefinitionWithArgs<"FocusItem", {
  itemId: String
}, Effect<{
  _tag: "CompletedFocusItem"
}, never, never>>

Message

constsource
/** Union of all messages the drag-and-drop component can produce. */
const Message: S.Union<[typeof PressedDraggable, typeof MovedPointer, typeof ReleasedPointer, typeof CancelledDrag, typeof ActivatedKeyboardDrag, typeof ResolvedKeyboardMove, typeof ConfirmedKeyboardDrop, typeof PressedArrowKey, typeof CompletedAutoScroll, typeof CompletedFocusItem]>

Model

constsource
/** Schema for the drag-and-drop component's state, tracking its unique ID, orientation, and current drag phase. */
const Model: Struct<{
  activationThreshold: Number
  dragState: Union<readonly [
    CallableTaggedStruct<"Idle", {}>,
    CallableTaggedStruct<"Pending", {
      containerId: String
      index: Number
      itemId: String
      origin: Struct<{
        screenX: Number
        screenY: Number
      }>
    }>,
    CallableTaggedStruct<"Dragging", {
      current: Struct<{
        clientX: Number
        clientY: Number
      }>
      itemId: String
      maybeDropTarget: Option<Struct<{
        containerId: String
        index: Number
      }>>
      origin: Struct<{
        screenX: Number
        screenY: Number
      }>
      sourceContainerId: String
      sourceIndex: Number
    }>,
    CallableTaggedStruct<"KeyboardDragging", {
      itemId: String
      sourceContainerId: String
      sourceIndex: Number
      targetContainerId: String
      targetIndex: Number
    }>
  ]>
  id: String
  orientation: Literals<readonly ["Horizontal", "Vertical"]>
}>

MovedPointer

constsource
/** The pointer moved during a drag, with collision detection results. */
const MovedPointer: CallableTaggedStruct<"MovedPointer", {
  clientX: Number
  clientY: Number
  maybeDropTarget: Option<Struct<{
    containerId: String
    index: Number
  }>>
  screenX: Number
  screenY: Number
}>

OutMessage

constsource
/** Union of all out-messages the drag-and-drop component can emit to its parent. */
const OutMessage: Union<readonly [
  CallableTaggedStruct<"Reordered", {
    fromContainerId: String
    fromIndex: Number
    itemId: String
    toContainerId: String
    toIndex: Number
  }>,
  CallableTaggedStruct<"Cancelled", {}>
]>

PressedArrowKey

constsource
/** The user pressed an arrow key during keyboard drag. */
const PressedArrowKey: CallableTaggedStruct<"PressedArrowKey", {
  direction: Literals<readonly ["Up", "Down", "Left", "Right", "NextContainer", "PreviousContainer"]>
}>

PressedDraggable

constsource
/** The user pressed a pointer on a draggable item. */
const PressedDraggable: CallableTaggedStruct<"PressedDraggable", {
  containerId: String
  index: Number
  itemId: String
  screenX: Number
  screenY: Number
}>

ReleasedPointer

constsource
/** The pointer was released. */
const ReleasedPointer: CallableTaggedStruct<"ReleasedPointer", {}>

Reordered

constsource
/** Emitted when a drag completes with a valid drop target. The parent uses this to commit the reorder. */
const Reordered: CallableTaggedStruct<"Reordered", {
  fromContainerId: String
  fromIndex: Number
  itemId: String
  toContainerId: String
  toIndex: Number
}>

ResolveKeyboardMove

constsource
/** Resolves the next keyboard drag position by querying the DOM for adjacent sortable items and containers. */
const ResolveKeyboardMove: CommandDefinitionWithArgs<"ResolveKeyboardMove", {
  currentContainerId: String
  currentIndex: Number
  direction: Literals<readonly ["Up", "Down", "Left", "Right", "NextContainer", "PreviousContainer"]>
  itemId: String
}, Effect<{
  _tag: "ResolvedKeyboardMove"
  targetContainerId: string
  targetIndex: number
}, never, never>>

ResolvedKeyboardMove

constsource
/** The ResolveKeyboardMove Command resolved the next keyboard drag position. */
const ResolvedKeyboardMove: CallableTaggedStruct<"ResolvedKeyboardMove", {
  targetContainerId: String
  targetIndex: Number
}>

SubscriptionDependencies

constsource
/** Schema describing the subscription dependencies for document-level drag tracking. */
const SubscriptionDependencies: Struct<{
  autoScroll: Struct<{
    clientY: Number
    isDragging: Boolean
  }>
  documentEscape: Struct<{
    dragActivity: Literals<readonly ["Idle", "Active"]>
  }>
  documentKeyboard: Struct<{
    dragActivity: Literals<readonly ["Idle", "Active"]>
  }>
  documentPointer: Struct<{
    dragActivity: Literals<readonly ["Idle", "Active"]>
    orientation: Literals<readonly ["Horizontal", "Vertical"]>
  }>
}>

subscriptions

constsource
/** Document-level subscriptions for pointer and keyboard events during drag operations. */
const subscriptions: Subscriptions<DragAndDrop.Model, {
  _tag: "CancelledDrag"
} | {
  _tag: "PressedDraggable"
  containerId: string
  index: number
  itemId: string
  screenX: number
  screenY: number
} | {
  _tag: "MovedPointer"
  clientX: number
  clientY: number
  maybeDropTarget: Option<{
    containerId: string
    index: number
  }>
  screenX: number
  screenY: number
} | {
  _tag: "ReleasedPointer"
} | {
  _tag: "ActivatedKeyboardDrag"
  containerId: string
  index: number
  itemId: string
} | {
  _tag: "ResolvedKeyboardMove"
  targetContainerId: string
  targetIndex: number
} | {
  _tag: "ConfirmedKeyboardDrop"
} | {
  _tag: "PressedArrowKey"
  direction: "Left" | "Right" | "Up" | "Down" | "NextContainer" | "PreviousContainer"
} | {
  _tag: "CompletedAutoScroll"
} | {
  _tag: "CompletedFocusItem"
}, Struct<{
  autoScroll: Struct<{
    clientY: Number
    isDragging: Boolean
  }>
  documentEscape: Struct<{
    dragActivity: Literals<readonly ["Idle", "Active"]>
  }>
  documentKeyboard: Struct<{
    dragActivity: Literals<readonly ["Idle", "Active"]>
  }>
  documentPointer: Struct<{
    dragActivity: Literals<readonly ["Idle", "Active"]>
    orientation: Literals<readonly ["Horizontal", "Vertical"]>
  }>
}>, never>

Stay in the update loop.

New releases, patterns, and the occasional deep dive.


Built with Foldkit.

© 2026 Devin Jameson