Component

Kanban Board

A generic multi-column stage board. Designed for recruiter pipelines, project workflows, and any process with discrete stages — with column accents, gate notes, and per-column card overflow.

Basic board

Pass columns, cards, getCardColumnId, and a renderCard function. Cards are distributed into the matching column automatically.

Applied2

Alice Chen

Eng II

Bob Okafor

Senior Eng

Phone Screen1

Carol Rivera

Eng I

Interview1

Dave Kim

Staff Eng

Offer1

Eve Patel

Eng II

With column accents and notes

Supply an accent color on any column def to draw a thin colored bar below the header. A note renders a gate description beneath the accent bar.

Applied2

Alice Chen

Eng II

Bob Okafor

Senior Eng

Phone Screen1

Schedule via Calendly

Carol Rivera

Eng I

Interview1

Dave Kim

Staff Eng

Offer1

Comp approval required

Eve Patel

Eng II

Overflow cap

Set cardCap to limit visible cards per column. Cards beyond the cap are hidden behind a +N more button; wire up onShowMore to open a drawer or expand the column.

Applied5

Alice Chen

Eng II

Bob Okafor

Senior Eng

Frank Wu

Eng II

Phone Screen1

Carol Rivera

Eng I

Interview1

Dave Kim

Staff Eng

Offer1

Eve Patel

Eng II

Installation

$pnpm add @refraction-ui/react

Usage

tsx
import { KanbanBoard, KanbanCard } from '@refraction-ui/react'
import type { KanbanColumnDef } from '@refraction-ui/react'

const stages: KanbanColumnDef[] = [
  { id: 'applied',  title: 'Applied',       accent: '#6366f1' },
  { id: 'screen',   title: 'Phone Screen',  note: 'Schedule via Calendly' },
  { id: 'offer',    title: 'Offer',         accent: '#22c55e' },
]

const candidates = [
  { id: '1', name: 'Alice Chen',   stageId: 'applied' },
  { id: '2', name: 'Bob Okafor',   stageId: 'screen'  },
  { id: '3', name: 'Carol Rivera', stageId: 'offer'   },
]

export function Pipeline() {
  return (
    <KanbanBoard
      columns={stages}
      cards={candidates}
      getCardColumnId={(c) => c.stageId}
      getCardKey={(c) => c.id}
      renderCard={(c) => (
        <KanbanCard clickable>
          <p className="font-medium">{c.name}</p>
        </KanbanCard>
      )}
      cardCap={5}
    />
  )
}

Props

PropTypeDefaultDescription
columnsKanbanColumnDef[]--Column definitions in left-to-right render order. Each def has `id`, `title`, optional `accent` color, and optional `note`.
cardsT[]--All cards to distribute across columns.
getCardColumnId(card: T) => string--Selector returning the column id for a card.
getCardKey(card: T) => string--Selector returning a unique React key for a card.
renderCard(card: T, column: KanbanColumnDef) => ReactNode--Render function for a single card inside a column.
cardCapnumber5Maximum visible cards per column. Cards beyond the cap are hidden behind a "+N more" button.
onCardClick(card: T) => void--Optional click handler — pass to renderCard as needed.
columnHeader(def: KanbanColumnDef, count: number) => ReactNode--Override the default column header (icon + title + count badge).
onShowMore(columnId: string) => void--Called when the user clicks "+N more" for a column.
classNamestring--Additional CSS classes for the board container.