Container wraps a core SnapSort container and provides it to descendant Item and nested Container components through React context.
import { Container, Item } from "@snap-engine/snapsort-react";
<Container config={{ direction: "column", groupID: "tasks" }}>
<Item itemId="task-1">Task 1</Item>
</Container> Props
type ContainerProps = {
children?: ReactNode;
className?: string;
config: ContainerConfig;
containerObject?: SnapSortContainer | null;
itemId?: string;
locked?: boolean;
selected?: boolean;
metadata?: Record<string, unknown>;
style?: CSSProperties;
}; | Prop | Default | Description |
|---|---|---|
children | undefined | Item and nested container content. |
className | "" | Extra class string applied to the rendered element. |
config | Required | SnapSort container configuration. |
containerObject | null | Optional existing core container object. The component does not own its creation. |
itemId | undefined | Required when this container is a sortable entry inside another container. |
locked | true | Keeps a nested container from being dragged. Set to false to make it draggable. |
selected | false | Consumer-owned selection flag for multi-item drags. Only meaningful when locked is false. |
metadata | {} | Metadata assigned to the container object and exposed in callback events. |
style | undefined | Inline styles merged onto the container element. |
Container forwards a ref to its core object and renders a div with snapsort-container plus a mode-specific class.
Config
| Option | Default | Description |
|---|---|---|
mode | "euclidean" | Drag/drop mode for this tree: "euclidean", "progressive", "insertion", or "swap". |
strategy | Resolved from mode | Advanced custom { dropTarget, lifecycle } strategy pair that overrides mode. |
direction | "column" | Main layout direction: "column" or "row". |
groupID | "default-group" | Containers with the same group can exchange items. |
mainAxisAlign | "start" | Main-axis alignment for virtual placement. Supports "start" and "center". |
name | Generated | Human-readable container name. |
animation | Default 100ms animations | Reorder, drop, and click-move animation settings. Set to null to disable configured animations. |
disableFlip | false | Disables FLIP movement animation. |
noDrop | false | Prevents the container from being a drop target. Useful for root layout containers. |
dropArea | false | Treats the container as an explicit drop area for collision filtering. |
callbacks | Default DOM callbacks | Hooks for DOM, framework state, and custom ghost behavior. |
Mode is resolved from the root container when a drag starts, so nested containers in one drag tree should use the same mode.
Callbacks
| Callback | When it runs |
|---|---|
onItemMove(event) | An item moves to a new container or index. Preferred for state-backed lists because it includes both from and to. |
onItemSwap(event) | Swap mode commits a pairwise slot exchange. Falls back to two onItemMove events when undefined. |
onItemInsert(event) | An item is inserted into a container; this is the lower-level fallback for onItemMove. |
onItemRemove(event) | An item is removed through removeItem(id). |
onDragStart(event) | A drag is starting. Return false to veto it. |
onDragEnd(event) | A drag has ended and its mutation has committed. |
onDropTargetChange(event) | The prospective drop container or index changed. Fires on the root container. |
canDrop(event) | Resolves whether this container accepts the current drag. Keep it cheap. |
onGhostInsert(event) | A ghost item or insertion marker is inserted or moved. |
onGhostRemove(event) | A ghost item or insertion marker is removed. |
createGhost(event) | Creates a flow ghost or insertion/swap marker. |
flushMutation(mutation) | Runs a structural callback inside React’s synchronous commit. Supplied automatically. |
awaitMutation() | Deprecated compatibility callback. |
For state-backed lists, update React state synchronously in onItemMove or onItemSwap. The adapter wraps structural callbacks in flushSync, allowing SnapSort to read committed DOM before paint. Do not defer these updates with transitions, timers, animation frames, or promises.
Imperative Ref
Container components forward refs to their core container object.
import { useRef } from "react";
import { Container, Item } from "@snap-engine/snapsort-react";
import type { Container as SnapSortContainer } from "@snap-engine/snapsort";
export function ClickMove() {
const source = useRef<SnapSortContainer>(null);
const target = useRef<SnapSortContainer>(null);
function moveToTarget(id: string) {
if (!source.current || !target.current) return;
source.current.moveItem(id, target.current, target.current.numberOfItems);
}
return (
<>
<Container ref={source} config={{ direction: "column", groupID: "cards" }}>
<Item itemId="card-1">
<button type="button" onClick={() => moveToTarget("card-1")}>Move card</button>
</Item>
</Container>
<Container ref={target} config={{ direction: "column", groupID: "cards" }} />
</>
);
} The ref exposes moveItem, removeItem, numberOfItems, groupID, direction, mainAxisAlign, dropArea, mode, config, callbacks, and dragSession from the core container.