Expo Kanban
On this page6 sections

API reference

Architecture

The whole package is nine source files. This page is the map — useful when you need to debug a gesture or fork the component.

Entry point

Everything starts in src/index.tsx.

The board is a function component generic over T extends ItemType and K. It keeps two pieces of React state: the current destination column and the dragged item. Shared values for X and Y live in Reanimated.

constants.ts
const SCREEN_WIDTH = Dimensions.get('screen').width;

const columnContainerWidth = props.columnWidth ?? SCREEN_WIDTH * 0.8;
const scrollTriggerWidth = SCREEN_WIDTH * 0.3;
const edgeColumnOff = columnContainerWidth * 1.5 - SCREEN_WIDTH * 0.5;
const marginAlign = (SCREEN_WIDTH - columnContainerWidth) / 2;

const columnPadding = props.gapBetweenColumns ?? 12;

edgeColumnOff and marginAlign convert between screen pixels and the horizontal list's offset space. They are what make the first column appear centered with neighbors peeking in.

Components

Two components: the board and the card wrapper.

The board renders one View per column. Each column contains the header, the count, and a vertical FlatList. Cards are wrapped in DataCard, a memoized Pressable that measures its own window position and hides itself while its preview is being dragged.

Why measure in window?

The drag overlay is rendered as an absolute sibling of the column list. Window coordinates let it start exactly where the card was, regardless of scroll offsets or parent padding.

Hooks

Each hook has one job.

  • useDragGesture — gesture lifecycle and drop decisions
  • useColumnPagination — horizontal paging with a throttle
  • useLayoutAnimation — LayoutAnimation presets with Android support

The hooks are documented individually on the Hooks page.

Utilities

Shared drag state for descendants.

DraggedCardContext creates a React context holding the lifted card and the drag shared values. The board provides it, and cards or overlays can consume it with useDragContext.

Data flow

From finger down to your state update.

flow.txt
long press
  → DataCard.onLongPress
  → measureInWindow()
  → setDragCard({ props, x, y, width, columnIndex, id })
  → gesture activates on touch move
  → dragX / dragY shared values update
  → near edge? paginate('left' | 'right')
  → release
  → drop()
  → onDragEnd({ fromColumnIndex, toColumnIndex, itemId })

The board never updates columnData. It reports the indices and id, then waits for the parent to produce new columns. That keeps the component predictable and compatible with any state library.

File index

Every source file in the package.

src/index.tsxBoard container

Computes screen constants, renders the horizontal FlatList, wires the drag gesture, and draws the floating preview.

src/types.tsPublic types

KanbanBoardProps, columnDataType, ItemType, DraggedCardProps, and example header/item shapes.

src/components/DataCard.tsxCard wrapper

Memoized Pressable that measures itself on layout and starts a drag on long-press.

src/hooks/useDragGesture.tsGesture state

Creates the manual pan gesture, stores the dragged card, and calls onDragEnd after a successful drop.

src/hooks/useColumnPagination.tsPaging

Throttled scrollToOffset helper that pages left, right, or re-centers the board.

src/hooks/useLayoutAnimation.tsLayout animation

Configures React Native LayoutAnimation with an Android workaround.

src/utils/DraggedCardContext.tsxDrag context

React context that exposes the dragged card and shared drag coordinates.

Watch the typo

The layout animation option is spelled opacitiy in the source. It is documented as-is so a future fix is easy to spot.