Container

Svelte Container component props, configuration, callbacks, and imperative API.

Container wraps a core SnapSort container and provides it to descendant Item and nested Container components through Svelte context.

<script lang="ts">
  import { Container, Item } from "@snap-engine/snapsort-svelte";

  const tasks = [
    { id: "design", label: "Design" },
    { id: "build", label: "Build" },
  ];
</script>

<Container
  config={{ direction: "column", groupID: "tasks" }}
  items={tasks}
  getItemId={(task) => task.id}
>
  {#snippet entry(task)}
    <Item itemId={task.id}>{task.label}</Item>
  {/snippet}
</Container>

Each entry must render exactly one Item or nested Container whose itemId matches getItemId(entry).

Props

type ContainerProps<T> = {
  config: ContainerConfig;
  items?: T[];
  getItemId?: (entry: T) => string;
  entry: Snippet<[T]>;
  ghost?: Snippet<[GhostInsertEvent]>;
  before?: Snippet;
  after?: Snippet;
  itemId?: string;
  container?: Container;
  locked?: boolean;
  selected?: boolean;
  className?: string;
  metadata?: Record<string, unknown>;
};
PropDefaultDescription
configRequiredSnapSort container configuration.
items[]Data entries for this container. Omit for containers that only receive drops or hold static children.
getItemId(entry) => entry.idStable ID for each entry.
entryRequiredRenders one Item or nested Container for each entry.
ghostDefault spacerRenders flow-mode target ghosts. Custom snippets should render <Ghost {event}>...</Ghost>.
beforeundefinedNon-sortable content rendered before entries.
afterundefinedNon-sortable content rendered after entries.
itemIdundefinedRequired when this container is rendered as a sortable entry inside another container.
containerBindableReceives the created core container object.
lockedtrueKeeps the container itself from being dragged when nested. Set to false for draggable nested containers.
selectedfalseConsumer-owned selection flag for multi-item drags. Only meaningful when locked is false.
className""Extra class string applied to the rendered element.
metadata{}Metadata assigned to the container object and exposed in callback events.

Container renders a div with snapsort-container plus a mode-specific class.

Config

OptionDefaultDescription
mode"euclidean"Drag/drop mode for this tree: "euclidean", "progressive", "insertion", or "swap".
strategyResolved from modeAdvanced 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".
nameGeneratedHuman-readable container name.
animationDefault 100ms animationsReorder, drop, and click-move animation settings. Set to null to disable configured animations.
disableFlipfalseDisables FLIP movement animation.
noDropfalsePrevents the container from being a drop target. Useful for root layout containers.
dropAreafalseTreats the container as an explicit drop area for collision filtering.
callbacksDefault DOM callbacksHooks 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

CallbackWhen 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 marker-kind ghost for insertion or swap mode.
flushMutation(mutation)Runs a structural callback inside the adapter’s synchronous Svelte commit. Supplied automatically.
awaitMutation()Deprecated compatibility callback.

For state-backed lists, update your Svelte arrays in onItemMove or onItemSwap. The adapter uses flushSync, allowing SnapSort to read final DOM geometry before paint.

Bindable Core Object

Use bind:container when buttons, keyboard handlers, or other controls need the core container API.

<script lang="ts">
  import { Container, Item } from "@snap-engine/snapsort-svelte";
  import type { Container as SnapSortContainer } from "@snap-engine/snapsort";

  let source: SnapSortContainer | undefined = $state();
  let target: SnapSortContainer | undefined = $state();
  let sourceCards = $state([{ id: "card-1", label: "Card 1" }]);
  let targetCards = $state<{ id: string; label: string }[]>([]);

  function moveToTarget(id: string) {
    if (!source || !target) return;
    source.moveItem(id, target, target.numberOfItems);
  }
</script>

<Container
  bind:container={source}
  config={{ direction: "column", groupID: "cards" }}
  items={sourceCards}
  getItemId={(card) => card.id}
>
  {#snippet entry(card)}
    <Item itemId={card.id}>
      <button type="button" onclick={() => moveToTarget(card.id)}>Move card</button>
    </Item>
  {/snippet}
</Container>

<Container
  bind:container={target}
  config={{ direction: "column", groupID: "cards" }}
  items={targetCards}
  getItemId={(card) => card.id}
>
  {#snippet entry(card)}
    <Item itemId={card.id}>{card.label}</Item>
  {/snippet}
</Container>
APIDescription
container.moveItem(id, targetContainer, index)Moves an item into another container or index.
container.removeItem(id)Removes an item by itemId or internal object ID.
container.numberOfItemsNumber of tracked child items.
container.groupIDConfigured group ID.
container.directionGets or sets "column" or "row".
container.mainAxisAlignGets or sets "start" or "center".
container.dropAreaGets or sets explicit drop-area behavior.
container.modeGets or sets the drag/drop mode.
container.configLive ContainerConfig object.
container.callbacksConfigured callback object.
container.dragSessionActive DragSession, or null.

Custom Ghost

Use a ghost snippet with Ghost to customize the flow spacer in euclidean or progressive mode.

<Container config={{ mode: "progressive", direction: "row" }} items={tiles}>
  {#snippet entry(tile)}
    <Item itemId={tile.id}>{tile.text}</Item>
  {/snippet}

  {#snippet ghost(event)}
    <Ghost {event}>
      <span class="tile-ghost">{event.originalItemId}</span>
    </Ghost>
  {/snippet}
</Container>