Utility · DragDrop
DragDrop
Pointer + keyboard drag and drop. Soma owns the gesture coordinator and
ARIA announcements via the global Announce service. Eidos
paints the visual states (data-dragging ghosts the source,
data-accepting highlights compatible targets,
data-dragover tints the hover target with the accent color).
parts {compiled.parts.order.length}
events {events.length}
sizes 5
cards {totalItems}
columns {Object.keys(columns).length}
handleDrop(e as DropEvent<{ from: string }>)}
>
{#snippet children(snippetProps)}
{@const { active } = snippetProps}
{#each Object.keys(columns) as colKey (colKey)}
{#snippet children(_dropSnippet)}
{COL_LABELS[colKey]}
· {columns[colKey].length}
{#each columns[colKey] as item (item.id)}
⋮⋮ {item.label}
{/each}
{/snippet}
{/each}
trace
{#if active}
{active.label} · from {(active.data as { from?: string }).from}
{:else if trace.length === 0}
drag cards across columns · keyboard: Tab → Space → arrows → Enter / Escape
{:else}
{#each trace.slice(0, 3) as entry}
{entry.event} · {entry.family}{entry.intent ? ' · ' + entry.intent : ''}
{fmtTime(entry.at)}
{/each}
{/if}
{#if active}
⋮⋮ {active.label}
{/if}
{/snippet}
(tab = 'live')}>Live
(tab = 'api')}>API 4
(tab = 'morfo')}>
morfo
{partsList.length}p · {events.length}e
(tab = 'sema')}>
sema
{events.length}
(tab = 'recipe')}>Recipe
(tab = 'a11y')}>A11y
{#if tab === 'live'}
Controls
Soma coordinates the gesture (pointer + keyboard), filters drop targets by accept, and announces via the global Announce service. Eidos paints the visual states.
soma behaviour
moveBuffer
{#each [0, 5, 12, 24] as n (n)}
(moveBuffer = n)}>{n}px
{/each}
announceEnabled
{announceEnabled ? 'SR announcements on' : 'silent'}
eidos visual props
size
{#each ['xs', 'sm', 'md', 'lg', 'xl'] as s (s)}
(size = s as DragDropSize)}>{s}
{/each}
color
{#each ['primary', 'secondary', 'neutral', 'affirm', 'fulfill', 'risk', 'threat', 'loss'] as c (c)}
(color = c as DragDropColor)}>{c}
{/each}
eidos
visual · DragDrop + Draggable + Droppable + Preview
svelte
{eidosSnippet}
{/if}
{#if tab === 'api'}
API reference
4 parts: Provider · Draggable · Droppable · Preview. The Provider does NOT own the data — consumer receives onDrop and mutates state.
Provider (DragDrop)
Prop Type Default Description
onDragStart · onDragEnd · onDrop callbacks — Gesture lifecycle hooks.
announceEnabled boolean true Emit SR announcements via the global Announce service.
size eidos 'xs' | 'sm' | 'md' | 'lg' | 'xl' 'md' Cascaded visual size.
color eidos ColorRole 'primary' Accent for drop targets + preview border + shadow.
Draggable
Prop Type Default Description
value string required Unique identifier returned in onDrop.
data DragData {'{}'} Arbitrary payload received in onDrop.
disabled boolean false Skip from drag gesture.
moveBuffer number 5 Pixels the pointer must move before drag is recognised.
textValue string aria-label/textContent Label for SR announcements.
Droppable
Prop Type Default Description
accept (data, value) => boolean () => true Filter — return false to skip this target.
disabled boolean false Disable drops.
textValue string — Label for SR announcements.
Snippet props
Snippet Key Type Description
Provider.children active ActiveDrag | null Info about the in-flight drag (value, data, label, pointer).
Provider.children cancel () => void Imperative cancel.
Draggable.children dragging boolean True while THIS draggable is the source.
Draggable.children handleProps object Spread on a child to restrict the drag handle.
Droppable.children over boolean Pointer/focus is over THIS target.
Droppable.children accepting boolean True for compatible targets while ANY drag is active.
{/if}
{#if tab === 'morfo'}
morfo
· declarative contract
Source: src/uix/morfo/components/drag-drop.ts.
Parts
Part Marker Element Role States Optional
{#each partsList as part (part.kebab)}
{part.kebab}
[{part.marker}]
<{part.defaultElement}>
{part.role ?? '—'}
{part.states.length ? part.states.join(' | ') : '—'}
{part.optional ? 'yes' : 'no'}
{/each}
Events declaration
name family verb sequence intent target
{#each events as action (action.name)}
{@const sem = action.semantic}
{@const intentDecl = 'intent' in sem ? sem.intent : undefined}
{@const intentStr = typeof intentDecl === 'string' ? intentDecl : intentDecl ? `fromProp:${(intentDecl as { fromProp?: string }).fromProp ?? '?'}` : '—'}
{action.name}
{sem.family}
{sem.verb ?? '—'}
{sem.sequence ?? 'pre'}
{intentStr}
{action.target}
{/each}
{/if}
{#if tab === 'sema'}
sema
· events
{#if events.length === 0}
DragDrop's SR feedback is delivered via the global Announce service rather than sema events — the perception is verbal, not audio cues.
{:else}
Name Family Verb Sequence Intent
{#each events as action (action.name)}
{@const intentDecl = 'intent' in action.semantic ? action.semantic.intent : undefined}
{action.name}
{action.semantic.family}
{action.semantic.verb ?? '—'}
{action.semantic.sequence ?? 'pre'}
{typeof intentDecl === 'string' ? intentDecl : '—'}
{/each}
{/if}
{/if}
{#if tab === 'recipe'}
Eidos recipe
Selectors at src/uix/eidos/components/drag-drop/drag-drop.css.
Selector Source What it paints
[data-drag-drop-draggable] eidos cursor: grab, touch-action: none.
[data-drag-drop-draggable][data-dragging] morfo Source ghosted (opacity: 0.4).
[data-drag-drop-droppable][data-accepting] morfo Compatible target outline (soft accent).
[data-drag-drop-droppable][data-dragover] morfo Hover target accent fill + inset border.
[data-drag-drop-preview] eidos Floating pointer follower — card chrome with accent border + shadow.
{/if}
{#if tab === 'a11y'}
Accessibility
Full keyboard parity with pointer — and SR announcements via the global
Announce service when announceEnabled is on.
Keyboard
Key Action
Tab Focus the next Draggable.
Space Lift the focused Draggable.
Arrow / Tab Navigate compatible Droppables.
Enter Drop on the current target.
Escape Cancel the lift.
Announcements (via global Announce)
Drag start → "Started dragging {`{item}`}"
Drag over Droppable → "Over {`{target}`}"
Drop → "Dropped {`{item}`} on {`{target}`}"
Cancel → "Cancelled"
{/if}