KQ-1723 · BLOCKER/CHAINS

Blocker Chains

A kanban board whose blocked cards hang a thin chain to the card they wait on: quadratic catenaries drawn under the cards with a fixed length, so dragging a card pulls its chains taut and bringing it closer lets them droop. Moving a blocker into Done snaps its chains loose — the free end swings down from the waiting card as a damped pendulum and fades on the exit ease — while the freed card lifts on springs.snap with an unblocked glow and settles back on springs.glide, and every card that moved FLIPs to its place on glide. Cards share one roving tab stop: arrows move, Space lifts and drops, Escape puts back, B shows every chain, L links a blocker, and Tab reaches a card's chain chips where Enter jumps to the blocker as a bead runs along the chain and Delete unlinks.

KQ-1723 · BLOCKER/CHAINS

Fieldline 4.2

Release board · 10 cards

5 blocked1 loop

Up next

3
  • FLD-214

    Offline map tiles

  • FLD-216

    Rename tenant ids

  • FLD-217

    Backfill audit log

In progress

3
  • FLD-207

    Storage layer v2

  • FLD-209

    Crew roster sync

  • FLD-211

    Push token refresh

Review

2
  • FLD-205

    Schema migration 31

  • FLD-203

    Sign-in rate limits

Done

2
  • FLD-201

    Crash on resume

  • FLD-202

    Upgrade build tools

Arrows move between cards. Space lifts a card, arrows carry it, Space drops it and Escape puts it back. L links a blocker, B shows every chain, and Tab reaches a card's chains: Enter jumps to the blocker, Delete unlinks.

5 blocked · 1 loop · chains on focus

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/blocker-chains

Props

columns
BlockerColumn[]
default defaultBlockerColumns
The columns, left to right: { id, title, done? }. A done column finishes work, and the chains its new cards held snap loose.
cards / defaultCards
BlockerCard[]
default — / defaultBlockerCards
The cards, controlled or initial, in column order: { id, title, column, blockedBy?, assignee?, since? }.
onCardsChange
(cards: BlockerCard[], change: BlockerChange) => void
default —
Fires with the whole board after a move, a link or an unlink, and what changed.
onMove
(move: { cardId, from, to, index }) => void
default —
Fires from the drop, pointer or keyboard, that moved a card.
onLink
(blockedId: string, blockerId: string, info: { circular: boolean }) => void
default —
Fires when a blocker is linked by the handle or by L; circular says the new chain closes a loop.
onUnlink
(blockedId: string, blockerId: string, reason: "done" | "removed") => void
default —
Fires when a chain comes off: its blocker reached a done column, or Delete removed it.
showAll / defaultShowAll
boolean
default — / false
Every chain in full, rather than only the hovered or focused card's (the rest stay faint).
onShowAllChange
(showAll: boolean) => void
default —
Fires from the Chains switch or the B key.
chainStyle
"links" | "thread" | "beads"
default "links"
How a chain is drawn: hollow interlocking links, one fine thread, or round beads.
cardStyle
"raised" | "flat" | "outline"
default "raised"
Card surface: raised with a shadow, a flat tint, or an outline on the board colour.
accent
string
default "var(--accent-bright)"
Highlighted chains and shackles, the drop wash, the switch and link mode. Any CSS colour.
now
number
default Date.UTC(2026, 9, 16, 9)
The moment a card's `since` is read against for "blocked 3d", in ms. Never the wall clock.
title
string
default "Fieldline 4.2"
The board's heading.
subtitle
string
default "Release board"
One line under the heading, followed by the card count.
status
"ready" | "loading" | "error"
default "ready"
Whether the board has loaded: loading shows skeleton columns, error a message with Try again.
onReload
() => void
default —
Try again was pressed after the board failed to load.
disabled
boolean
default false
Read-only: nothing moves or links, chains still show.
className
string
default —
Classes for the outer container.