Skip to content
Native Animation
Kanban Drag Cards animation preview

This preview uses fictional demo content. See the props below for the customization options available in this component.

npx nativeanimation add kanban-drag-cards

Kanban Drag Cards

A drag-to-reorder task board with live insertion gaps and configurable columns, fonts, column width ratio, and lift tilt.

$9 for this animation

Add to your project

Copy the component and its assets into your app with the Native Animation CLI, or paste the agent prompt into Claude Code, Codex or Cursor once the MCP server is connected.

About this animation

A drag-to-reorder task board with live insertion gaps and configurable columns, fonts, column width ratio, and lift tilt.

Why this one

A task feels lifted out of the board, rather than copied onto a rigid drag layer. Neighboring tasks make room with springs, the viewport follows the finger across columns, and a green eight-stroke celebration belongs specifically to completion. The Nimbus demo adds editorial sprint typography, realistic tasks, overlapping team avatars, and a light/dark theme switch.

How it works

  1. Measure the container with onLayout; each column takes 78% of the board width. Horizontal scrolling reveals the next column. Vertical scrolling keeps larger task lists reachable.
  2. A 280 ms long press lifts a task to 1.02× scale with a subtle tilt (up to 3° by default). A manually activated pan shares recognition with the hold; a competing Gesture Handler tap opens the move menu.
  3. Keep task order, drag coordinates, insertion index, viewport offset, and interaction phase on the UI thread. The phases are rest → lifted → dragging → dropping → rest.
  4. Derive neighboring task positions from the shared order and insertion slot. Keep a dashed placeholder at the original position until release. A frame callback scrolls at up to 550 points/second within 40 points of either edge.
  5. Settle the task with a { damping: 33, stiffness: 260, mass: 1, overshootClamping: true } spring and inherited horizontal velocity. Commit the board to React and call onChange after the spring settles. The card settles without oscillation. Counters roll with fading outgoing digits.
  6. A completed column draws the kit's Lucide check with a Skia path trim and emits eight fine particles. Only one Skia canvas is used; static kit icons are SVG images.

Install

Copy this folder without demo/ into your project, then install SDK-compatible packages:

npx expo install react-native-reanimated react-native-worklets react-native-gesture-handler expo-image @shopify/react-native-skia

Follow your Expo SDK's Reanimated setup. On web, initialize Skia/CanvasKit before importing this component (for example, a deferred WithSkiaWeb entry). The host must provide loaded font families if custom fonts are passed. Icons: Lucide (ISC); the copied paths are in icons.ts.

Usage

import { KanbanDragCards, type KanbanColumn } from './kanban-drag-cards';

const columns: KanbanColumn[] = [
  {
    id: 'planned', title: 'Planned', color: '#7C5CFF',
    cards: [{ id: 'task', title: 'Polish the welcome flow', tag: 'Design',
      color: '#7C5CFF', assignee: 'AM', date: 'Oct 14' }],
  },
  { id: 'done', title: 'Done', color: '#10B981', completed: true, cards: [] },
];

export function Board() {
  return <KanbanDragCards columns={columns} />;
}
const boardRef = useRef<KanbanDragCardsRef>(null);

<KanbanDragCards
  ref={boardRef}
  columns={columns}
  colorScheme="auto"
  columnWidthRatio={0.8}
  holdDuration={320}
  maxTilt={3}
  springDamping={33}
  onChange={(nextColumns, movedCardId) => saveBoard(nextColumns, movedCardId)}
/>;

boardRef.current?.move('task', 'done', 0);

The parent must give the board a bounded height. The component owns its order; remount with a new key when replacing the initial dataset. All card and column IDs must be unique. Color values use six-digit hex strings because translucent tints derive from them.

Props

PropTypeDefaultDescription
columnsreadonly KanbanColumn[]RequiredInitial columns, cards, and completion flags
fontFamilystringSystemBody and menu font
headingFontFamilystringfontFamilyTask and column headings
monoFontFamilystringSystemCounts and due dates
colorScheme'light' | 'dark' | 'auto''light'Surface and text theme
columnWidthRationumber0.78Column width, clamped to 0.65–0.86
holdDurationnumber280Lift delay in milliseconds
maxTiltnumber3Horizontal-velocity tilt limit in degrees
springDampingnumber33Drop spring damping; stiffness is 260 and mass is 1. Values below the damping needed for ζ ≥ 0.85 are raised to that minimum; overshoot is clamped.
onChange(columns, movedCardId) => void—Complete ordered board after settlement
accessibilityLabelstring'Task board'Board label
styleStyleProp<ViewStyle>—Root container style
testIDstring—Testing identifier

KanbanCard includes id, title, tag, color, assignee, date, optional comments, attachments, and optional [completed, total] subtasks. KanbanColumn includes id, title, color, cards, and optional completed.

Ref methods: move(cardId, columnId, index = 0), focus(columnId), and reset(). reset() restores the initial board and cancels an active scripted move; it does not call onChange.

Demo timeline

The autoplay loop lasts 5.2 seconds. At 100 ms it restores the sprint and focuses In progress; at 380 ms it lifts “Polish onboarding empty states,” traverses the right edge into Review, and drops it. At 1,750 ms it lifts “Tighten the team invite flow” into Done. Its check and green burst start as the drop settles, within the first three seconds. The demo owns and cleans up its timers; the component has no autoplay prop.

Compatibility

Built for Expo SDK 58, React Native 0.88.0, Reanimated 4.7.1, Worklets 0.13.0, Gesture Handler 3.3, expo-image 58, and Skia 2.14.0. Uses the installed Expo Go modules; no additional native dependency is introduced. Supports iOS, Android, and web.

Accessibility

Every task exposes a button role, a descriptive label, and an activation action for its Move to menu. Tapping is handled by Gesture Handler, so the alternative also works after native gesture recognition. Menu rows and the close control provide at least 44-point targets. With reduced motion enabled, task moves use a 180 ms fade; tilt, lift scaling, edge auto-scroll, and particles are disabled. Tap-to-move still navigates to the destination immediately. The menu is marked as modal for accessibility.

All springs set mass: 1 explicitly and clamp overshoot. Lift, tilt, press feedback, and neighboring task reflow use damping 35 and stiffness 300 (ζ ≈ 1.01). Drop springs use damping 33 and stiffness 260 by default (ζ ≈ 1.02), with a damping floor of 1.7 * Math.sqrt(260) (ζ ≥ 0.85), including custom springDamping values. Horizontal drops inherit release velocity and stop at the destination without bouncing past it.