Kanban

列をまたいでアイテムをドラッグ&ドロップで整理できる、カスタマイズ可能なかんばんコンポーネント。

カードを列内で並べ替えたり、列をまたいで移動したり、列そのものを並べ替えたりできるドラッグ&ドロップ対応のかんばんです。@dnd-kit を基盤にしつつ、Base UI の useRender パターンで構築しているため、各パーツは render prop で任意の要素に差し替えられます。

Backlog

3
Audit color tokensmedium
Draft onboarding copylow
Spec the empty stateshigh

In Progress

2
Build the kanban boardhigh
Wire up drag sensorsmedium

Done

1
Set up the registrylow
"use client"

import * as React from "react"

インストール

pnpm dlx shadcn@latest add https://ui.tyap.me/r/styles/base/kanban.json

使い方

import {
  Kanban,
  KanbanBoard,
  KanbanColumn,
  KanbanColumnContent,
  KanbanColumnHandle,
  KanbanItem,
  KanbanItemHandle,
  KanbanOverlay,
} from "@/components/ui/kanban"
<Kanban
  value={columns}
  onValueChange={setColumns}
  getItemValue={(item) => item.id}
>
  <KanbanBoard>
    {Object.entries(columns).map(([id, items]) => (
      <KanbanColumn key={id} value={id}>
        <KanbanColumnHandle>
          <h3>{id}</h3>
        </KanbanColumnHandle>
        <KanbanColumnContent value={id}>
          {items.map((item) => (
            <KanbanItem key={item.id} value={item.id}>
              <KanbanItemHandle>{item.content}</KanbanItemHandle>
            </KanbanItem>
          ))}
        </KanbanColumnContent>
      </KanbanColumn>
    ))}
  </KanbanBoard>
  <KanbanOverlay>
    <div className="bg-muted size-full rounded-md" />
  </KanbanOverlay>
</Kanban>

value は「列ID → アイテム配列」のレコードです。ドラッグ操作の結果は onValueChange で新しいレコードとして返されます。列内・列間の並べ替え、そして列自体の並べ替えはすべてコンポーネントが面倒を見ます。

サンプル

列の並べ替え + オーバーレイ

KanbanColumnHandle を置くと列ごと並べ替えられます。KanbanOverlay に関数を渡すと、ドラッグ中のゴースト要素を「列かアイテムか」で出し分けられます。

To Do

Define the API surface
Sketch the column layout

Doing

Implement drag overlay
Polish the handles

Shipped

Publish to the registry
"use client"

import * as React from "react"

API リファレンス

Kanban

かんばんのコンテキストを提供し、列とアイテムの状態を管理するルートコンポーネントです。

PropTypeDefaultDescription
valueRecord<string, T[]>-必須。列とそのアイテムの現在の状態。
onValueChange(value: Record<string, T[]>) => void-必須。列内・列間でアイテムが移動したときに呼ばれます。
getItemValue(item: T) => string-必須。アイテムの一意な識別子を返す関数。
onMove(event: KanbanMoveEvent) => void-指定すると内部での再配置を行わず、アイテムの配置を呼び出し側に委ねます。
modifiersModifiers-dnd-kit の modifier を渡します。
renderuseRender.RenderProp-ルート要素を任意の要素/コンポーネントに差し替えます。
classNamestring-コンテナの追加クラス。

KanbanBoard

列を横並びにするコンテナです。

PropTypeDefaultDescription
renderuseRender.RenderProp-ボード要素を差し替えます。
classNamestring-ボードの追加クラス。

KanbanColumn

ボード内の個々の列です。

PropTypeDefaultDescription
valuestring-必須。列の一意な識別子。
disabledbooleanfalse列のドラッグを無効化します。
renderuseRender.RenderProp-列要素を差し替えます。
classNamestring-列の追加クラス。

KanbanColumnHandle

列のドラッグハンドルです(列を並べ替え可能にする場合に使用)。

PropTypeDefaultDescription
cursorbooleantrueドラッグ用カーソル(grab/grabbing)を付与します。
renderuseRender.RenderProp-ハンドル要素を差し替えます。
classNamestring-ハンドルの追加クラス。

KanbanColumnContent

列内でアイテムを縦に並べる領域です。

PropTypeDefaultDescription
valuestring-必須。この領域が属する列の識別子。
renderuseRender.RenderProp-コンテンツ要素を差し替えます。
classNamestring-コンテンツ領域の追加クラス。

KanbanItem

列内のドラッグ可能なアイテムです。

PropTypeDefaultDescription
valuestring-必須。アイテムの一意な識別子。
disabledbooleanfalseアイテムのドラッグを無効化します。
renderuseRender.RenderProp-アイテム要素を差し替えます。
classNamestring-アイテムの追加クラス。

KanbanItemHandle

個々のアイテムのドラッグハンドルです。

PropTypeDefaultDescription
cursorbooleantrueドラッグ用カーソル(grab/grabbing)を付与します。
renderuseRender.RenderProp-ハンドル要素を差し替えます。
classNamestring-ハンドルの追加クラス。

KanbanOverlay

ドラッグ中に表示されるゴースト要素です。children に関数を渡すと、ドラッグ対象(valuevariant)に応じて表示内容を切り替えられます。

PropTypeDefaultDescription
childrenReactNode | (({ value, variant }) => ReactNode)-オーバーレイの表示内容。
classNamestring-オーバーレイの追加クラス。