crispmeasured from Attio

Deals kanban

A pipeline board — a different layout from the table, with drag-and-drop between stages.

Not every object wants a table. A Deals pipeline is the same App Shell + Sidebar + view bar, but the body is a kanban Board instead of a Records Table — columns per stage, a card per deal. Drag a card between columns to move a deal; the header counts update live, and New Deal adds a card to a stage.

Composition

Lead2
Google
$120,000S
Airbnb
$42,000D
In progress2
Figma
$88,000K
Notion
$64,000I
Won2
Linear
$150,000G
Vercel
$96,000S
Lost1
Intercom
$30,000D

The board is driven the same controlled way as everything else — the parent owns the cards, and a drag calls onCardsChange with the reparented list:

const [cards, setCards] = useState(deals);

<Board
  columns={[
    { id: "lead", title: "Lead", accent: "#266df0" },
    { id: "progress", title: "In progress", accent: "#e0518f" },
    { id: "won", title: "Won", accent: "#22a565" },
  ]}
  cards={cards}
  onCardsChange={setCards}
  onNewCard={(columnId) => setCards((cs) => [...cs, newDeal(columnId)])}
  newCardLabel="New Deal"
  renderCard={(deal) => <DealCard deal={deal} />}
/>;

Same object, different lens: a table and a board are two views over one controlled list of records — swapping between them is swapping the component, not the data model.

On this page