React Overview
On this page
The React binding wraps SnapSort’s core objects in React components. Use it when React owns the rendered arrays and your component state remains the source of truth for item order.
Install
npm install @snap-engine/snapsort @snap-engine/asset-base react react-dom react, react-dom, and @snap-engine/asset-base are optional peers of
the unified package and are required only when you import the React binding.
Import
import {
Engine,
Container,
Ghost,
Handle,
Item,
} from "@snap-engine/snapsort/react";
import {
reduceRenderTree,
type ContainerCallbacks,
type RenderTreeEvent,
} from "@snap-engine/snapsort"; Wrap the sortable tree in an Engine, then render the application’s mixed RenderTree.entries sequence. The root callbacks synchronously pass item moves
and all three explicit ghost events through one reduceRenderTree state update.
Each keyed entry renders as a Ghost, a recursive child Container, or a leaf Item:
The excerpt assumes tasks and setTasks come from the useState RenderTree
setup, and TaskContainer is the recursive component shown on the Container page.
const applyTreeEvent = (event: RenderTreeEvent) => {
setTasks((current) => reduceRenderTree(current, event));
};
const callbacks = {
onItemMove: applyTreeEvent,
onGhostInsert: applyTreeEvent,
onGhostMove: applyTreeEvent,
onGhostRemove: applyTreeEvent,
} satisfies ContainerCallbacks;
<Engine id="tasks">
<Container itemId="tasks-root" config={{ callbacks }}>
{tasks.entries.map((entry) =>
entry.isGhost ? (
<Ghost key={entry.itemId} ghost={entry.ghost} />
) : entry.childTree ? (
<TaskContainer key={entry.itemId} entry={entry} />
) : (
<Item key={entry.itemId} itemId={entry.itemId}>
{entry.value.label}
</Item>
),
)}
</Container>
</Engine>; Here TaskContainer recursively renders entry.childTree with itemId={entry.itemId}. The root alone receives the structural
callbacks; see the Container page for the complete state and recursive component.
The callback count reflects ownership rather than item/ghost symmetry. A drag
produces one semantic onItemMove for its complete source-to-destination
transition. SnapSort itself creates, relocates, and removes ghosts, so React
must receive all three explicit ghost-presence callbacks; they happen to share
the applyTreeEvent function above.
Do not use these callbacks as a general CRUD API. An application Add or Delete
action updates tasks directly, and React mounting or unmounting the keyed Item synchronizes its core registration. Add onItemRemove: applyTreeEvent only when code invokes the core container.removeItem(id) command. RenderTreeEvent excludes ItemInsertEvent because a core insertion event
cannot supply the application value for a new RenderEntry<T>.
Engine creates or accepts a core Engine, assigns it to the rendered root, installs collision handling, and provides it through React context. Use useSnapSortEngine() when a descendant needs the current core engine.
Components
- Container — props, modes, callbacks, mutation timing, and the imperative ref API.
- Item — props, identity, metadata, selection, refs, and drag handles.
- Ghost — lifecycle state, rendering, geometry, customization, and DOM attributes.
- DragSession — shared gesture state, lifecycle phases, and mutable controls.
- Standard Callbacks — reusable destination policies.
Handle belongs inside an Item and limits where a drag can begin. Ghost renders any lifecycle GhostState from the mixed entry sequence and
binds its engine-owned ghostItem to that element. It covers source and target
spacers, insertion markers, and pointer previews. Do not render a ghost with Item, because a ghost is already attached to the core container by the drag
lifecycle.
For an insertion marker, Ghost derives an exact container-local rectangle
from the state’s zero-thickness gap. Its insertionMarker prop accepts the
complete { thickness, startInset, endInset } presentation contract. Custom
adapters use the framework-neutral insertionMarkerRect helper with the same
options; none of those paint choices affect candidate ranking.
Every wrapper accepts standard div attributes and forwards them to its DOM
element. style is merged after SnapSort’s structural flex/position defaults.
Core Types
Import callback events, configuration, metadata, and core object types from the framework-agnostic package:
import type { Engine as CoreEngine } from "@snap-engine/core";
import type {
Container as SnapSortContainer,
ContainerConfig,
DragEndEvent,
DragStartEvent,
DropPriorityEvent,
Item as SnapSortItem,
ItemMoveEvent,
ItemMetadata,
ItemSwapEvent,
} from "@snap-engine/snapsort"; For application-state, ghost, and callback examples, see the Container reference.
Subpath Exports
| Import path | Exports |
|---|---|
@snap-engine/snapsort/react/Engine | Engine, context, and useSnapSortEngine |
@snap-engine/snapsort/react/Container | Container components and context |
@snap-engine/snapsort/react/Ghost | Framework-owned lifecycle ghost view |
@snap-engine/snapsort/react/Item | Item components and context |
@snap-engine/snapsort/react/Handle | Handle |