Auto-Animate: Fleet Motion Patterns
@formkit/auto-animate 0.10.0 (3.2kB, zero deps) on six fleet list surfaces: the real DataTable.svelte copy (sort FLIP, filter, row add/remove, page-jump exclusion with animated show-amount), chat room re-sort, toast sibling-shift fix, notification bulk clear, file-grid reflow, tag chips + dropdown — plus controller enable/disable, reduced-motion no-op, the gotchas panel, and the source-cited options-baked-at-init verdict with its remount workaround.
enable() / disable() across all 0 registered surfaces. disable() is instant (in-flight animations cancel, removals clean up immediately) —
the fleet lever for density-heavy admin pages and per-surface opt-outs.data-table flagship
Fleet mapping: ui/DataTable.svelte — 22/22 apps, 126 consumers,
keyed rows. Sort flip = strongest FLIP demo in the fleet.
Name | Role | Team | Score |
|---|---|---|---|
| Astrid Berg | Coach | Junior | 87 |
| Bjørn Østli | Treasurer | Board | 92 |
| Camilla Dahl | Admin | Operations | 78 |
| Daniel Vik | Coach | Senior | 64 |
| Elise Hauge | Gear keeper | Operations | 81 |
The table-row transform question (upstream formkit/auto-animate#7)
Upstream says tables are "known broken" — the removal path's absolute-positioning
style reset historically fights display: table-row. Verdict from THIS
page: the flagship runs <tbody use:autoAnimate> directly — sort
flips, filter swaps and row add/remove animate, and removed rows clean up without
ghosts. See the README for the full verdict + the backport browser matrix.
chat-room-list
Fleet mapping: chatDerived.ts:115,128 + ChatRoomListPanel.svelte:181 — 21 apps. Highest-churn snap: every
incoming message re-sorts.
Sending a message to a non-top room re-sorts the list — watch the others glide
instead of jump. The rooms array is store-derived exactly like the fleet's chatDerived; the animation is store-agnostic.
toast-stack
Fleet mapping: ui/Toast.svelte:55 + toastStore.ts:48,54 —
22 apps. Enter/exit animated, mid-stack dismissal snaps siblings.
Today: transition: only — siblings SNAP
+ auto-animate on the container — siblings GLIDE
Dismiss the MIDDLE toast on both stacks. Left: the lower toast teleports up.
Right: it slides. Note the right stack keeps item entry instant — auto-animate
owns enter/exit/move for that container, so the fleet's per-item in:/out:
would come OFF the items in a real backport (keep the left stack's transition:fly AND the right's container action, and you get both effects fighting).
notification-list
Fleet mapping: ui/NotificationBell.svelte:121 (mark-all-read :110) — 22 apps. Zero animation on the most-visible navbar surface.
-
Vera commented on Roster plan
2m
-
Gear return overdue: 4 helmets
18m
-
Budget draft ready for review
1h
The empty-state row is part of the same keyed list surface — the bulk clear animates the list items out while the empty row fades in. All of it from one action on the container.
file-grid
Fleet mapping: media/GridView.svelte:45,57 + FileUploadModal.svelte:348 — 20 apps. Grid reflow snaps on
add/delete/move.
Grid + list views share one container action each; the view switch itself is a keyed-block remount (swap, not rearrangement — same exclusion logic as table page jumps). Open the Photos folder to see navigation.
tag-chips
Fleet mapping: forms/TagInput.svelte:70 + TagFilterChips.svelte:106 + Autocomplete.svelte:161 —
21 apps × 3 bespoke implementations → one action.
Remove a MIDDLE chip: siblings glide (vs the fleet's transition:scale chip, which animates itself but snaps its siblings). The dropdown opens/closes with zero hand-written transition code. The input holds a fixed w-32 slot so adding chips never reflows the row under your typing (the wrap-jank fix).
Gotcha workaround: changing options live
VERDICT (source-cited, 0.10.0): options are BAKED at init — moving the slider does
nothing until you remount. Svelte only re-delivers action params through an update hook the action itself must return
(actions.js: if (get_value && payload?.update)), and
autoAnimate's controller is frozen with just enable/disable/isEnabled/destroy (its options are written once, in the
factory). Extremes are unmistakable on purpose: 50ms ≈ instant, 1500ms ≈ syrup.
Remount is the documented pattern that applies the new duration.
Gotchas (from the capability scout)
use:autoAnimate={{ duration: x }} will NOT react to x changing — Svelte re-delivers action params only via an update hook the action must return itself (actions.js guards with payload?.update), and autoAnimate writes options once in its factory and freezes the controller. Live config changes need a remount: wrap the animated container in {#key configKey} — see the workaround section above.