Skip to main content
WireKit
Copy for LLM

Kanban

A board-and-column layout for task management, pipelines, and workflow visualization. Supports horizontal scrolling, WIP limits, intent-based column accents, and drag-and-drop integration.

Basic Usage

Simple kanban board
To Do 2
Design homepage
Write copy
In Progress 1
Build API
Done 1
Setup CI/CD

Intent-Based Column Accents

Color the top border to visually distinguish column stages:

Column intent variants
Backlog 4
Research competitors
Draft project brief
Schedule kickoff call
Prepare mood board
Active 2
Wireframe dashboard
API endpoint spec
Review 1
Auth flow PR
Complete 3
Repo bootstrap
CI pipeline setup
Style-guide v1

WIP Limits

Set a limit per column. The count badge turns danger when the column exceeds capacity:

WIP limit enforcement
In Progress 3/5
Refactor billing module
Localize checkout flow
Performance audit
Review 6/5
Onboarding redesign PR
Email-template refresh
Search index migration
Webhook retry logic
Audit-log viewer
Account-deletion endpoint

Add actions (like "Add item") below the cards:

Column with footer
To Do 1
Existing task

Custom Column Header

Replace the default header with your own content:

Custom header slot
Sprint 4

3 items

Plan retro agenda
Update release notes
Demo prep

Vertical Orientation

Stack columns vertically instead of horizontally:

Vertical kanban
Stage 1 2
Discovery interviews
Define success metrics
Stage 2 1
Approved roadmap

Reordering

Add sortable to the board and to each column you want to reorder. Cards can then be moved by dragging or by keyboard.

A sortable column
Backlog 3
Design homepage
Write copy
Build API

Give each card a data-sortable-id so the new order means something to your application. Without one, a card falls back to its position — which only works for a list your server addresses positionally.

What you receive

When a move finishes, the column dispatches one bubbling wirekit:sortable:reordered event:

{{-- 1. The event bubbles, so listen anywhere above the board. --}}
<div wire:wirekit:sortable:reordered="reorder($event.detail.order)">
    <x-wirekit::kanban sortable>
        {{-- 2. Each card names itself; the event carries these ids. --}}
        <x-wirekit::kanban-column label="Backlog" sortable>
            @foreach($tasks as $task)
                <x-wirekit::card :data-sortable-id="$task->id">
                    <x-wirekit::card.body>{{ $task->title }}</x-wirekit::card.body>
                </x-wirekit::card>
            @endforeach
        </x-wirekit::kanban-column>
    </x-wirekit::kanban>
</div>
// 3. The whole sequence arrives at once, so persist it as one statement.
public function reorder(array $order): void
{
    foreach ($order as $position => $id) {
        Task::whereKey($id)->update(['position' => $position]);
    }
}

The payload is { order, id, from, to }: the complete new sequence, plus which card moved and where from and to.

One event, at the end — not a swap per crossing. A stream of swaps makes the final state depend on the order the responses arrive in, which is network timing: wrong whenever two are in flight, and impossible to test. A drag cannot promise the order of its own intermediate steps, so it does not report them.

Kanban Board Props

Prop Type Default Description
orientation string 'horizontal' Layout direction: horizontal or vertical
sortable bool false Enable drag-and-drop data attributes

Kanban Column Props

Prop Type Default Description
label string|null null Column heading text. It also names the column's scrollable body and makes it a screen-reader landmark — see Accessibility
count int null Number of items (shown as badge)
intent string 'neutral' Top border accent: neutral, primary, success, warning, danger, info
limit int null WIP limit (badge turns danger when exceeded)
sortable bool false Enable drag-and-drop data attributes

Column Slots

Slot Description
default Card items inside the column
header Replace the default column header
footer Action area below the cards

Accessibility

  • Board: role="list" for the column collection
  • Column: <section role="listitem"> with aria-labelledby linking to the column label
  • Sortable: reordering is operable by keyboard as well as by pointer — see below
  • Each card is focusable and carries aria-roledescription="Sortable item" while a column is sortable
  • Column body: tabindex="0" and a focus ring in every configuration, so the scrolling card list is keyboard-reachable even when the cards inside hold no other focusable element (WCAG 2.1.1)
  • The column body becomes a screen-reader landmark only when the column has a label. It is then a role="region" under that same name. Without one it stays a plain focusable scroller — role="region" plus a name is a landmark, and a six-column board falling back to one built-in name would be six landmarks announcing the same thing, which axe reports as landmark-unique. Every column on this page is labeled, which is the shape to copy.

Keyboard Interaction

Key Action
Tab Move focus through cards
Space / Enter Lift the focused card, or drop the one you lifted
Move the lifted card one place later
Move the lifted card one place earlier
Escape Abandon the move and put the card back

Reordering by keyboard is part of the feature rather than an addition to it: a list that can only be reordered by dragging cannot be reordered at all by someone not using a pointer.

Styling a card while it moves

A card carries a state attribute for as long as it is in motion, so you can give it whatever treatment fits your board. Both are removed when the move ends or is abandoned:

Attribute While
data-sortable-dragging The card is being dragged with a pointer
data-sortable-lifted The card has been lifted with the keyboard and is being moved
/* 1. The two states are separate on purpose: a dragged card is under the
      pointer and already reads as "held", a lifted one has only the keyboard
      to say so and needs to say it more loudly. */
[data-sortable-dragging] { opacity: 0.5; }
[data-sortable-lifted]   { outline: 2px solid var(--color-wk-ring); }

Pitfalls

  • Give every card a data-sortable-id. Positional fallbacks are silent and correct until the list is filtered or paginated.
  • Persist the sequence you are handed, not a swap. The event gives you the whole order for exactly this reason.

Design Tokens

Token Used for
--font-wk-sans Kanban font family
--font-wk-heading-weight Column title weight
--text-wk-sm Column title + count badge font size
--color-wk-text Column title
--color-wk-bg-muted Column body background
--color-wk-border / --color-wk-border-subtle Column border + separator
--color-wk-accent / --color-wk-success / --color-wk-warning / --color-wk-danger Top-border accent per intent
--color-wk-ring / --color-wk-ring-offset Focus ring
--ring-wk-width / --ring-wk-offset Focus ring geometry
--border-wk-width Border width
--radius-wk-lg Column border radius

Was this page helpful?

Voting requires cookies or local storage. What we store