nerdsnipe-inc/advancedkanban
A Kanban board component for SwiftUI on iOS, iPadOS, and macOS. You bring
Add a board in 3 steps
1. Conform your card type to KanbanCard — it only needs Identifiable and Equatable:
import AdvancedKanban
struct ExampleTask: KanbanCard {
let id: UUID
var title: String
}2. Conform your column type to KanbanColumn — it owns an ordered cards array (order is the board's display order, no separate sort index needed), an optional wipLimit, and an isCollapsed flag the board toggles on tap:
struct Stage: KanbanColumn {
let id: UUID
var name: String
var cards: [ExampleTask] = []
var wipLimit: Int? = nil
var isCollapsed: Bool = false
}3. Call KanbanBoard with a binding to your columns and view builders for card and column-header content:
import SwiftUI
import AdvancedKanban
struct ContentView: View {
@State private var columns: [Stage] = [
Stage(id: UUID(), name: "To Do", cards: [ExampleTask(id: UUID(), title: "Write README")]),
Stage(id: UUID(), name: "In Progress", wipLimit: 3),
Stage(id: UUID(), name: "Done"),
]
var body: some View {
KanbanBoard(
columns: $columns,
wipLimitBehavior: .preventDrop,
onMove: { move in
// move.cardID / .sourceColumnID / .destinationColumnID / .destinationIndex
// — persist however you like (SwiftData, a network call, analytics).
},
// Optional: gives VoiceOver real column names ("Move to In
// Progress") instead of describing the column by its raw id.
columnTitle: { $0.name },
cardContent: { task in
Text(task.title).padding(8)
},
columnHeader: { stage in
Text(stage.name).font(.headline)
}
)
}
}That's a complete, draggable, keyboard- and VoiceOver-accessible board. The onMove closure fires after the board has already mutated your columns binding, so it's purely a hook for persistence — you never diff arrays yourself.
Features
- Cross-column drag and drop — pointer-driven reorder within and across
columns, with edge autoscroll when dragging near the board's horizontal edges.
- Keyboard move-mode — Tab to focus a card, Space to enter move mode,
arrow keys to move within or across columns, Return to commit, Escape to cancel and restore the card's original position. No mouse required.
- Native pointer support on macOS — cards respond to hover with a
theme-agnostic highlight (visible in light and dark themes alike) and a grab/grabbing cursor (macOS 15+, gracefully absent on 14), and the drag gesture's activation threshold is tuned per platform — tight for a precise pointer (mouse/trackpad), the standard looser threshold for touch. The board is built to be embedded in real, native Mac apps, not just tolerated on one.
- VoiceOver parity — every drag interaction has an equivalent
accessibility action (Move Up / Move Down / Move to \<Column\>) exposed through the rotor, so VoiceOver users get the same reordering power as pointer and keyboard users.
- WIP limits — set
wipLimitper column and choose.warnOnly(the
column renders warning styling but the drop still succeeds) or .preventDrop (the drop is rejected and the card animates back) via wipLimitBehavior.
- Column collapse — columns collapse to a narrow title+count strip on
tap; state lives on your own isCollapsed property, so it's easy to persist.
- Theming —
KanbanThemecovers chrome-level tokens (backgrounds,
borders, corner radii, spacing, WIP warning color, drag ghost opacity, drop animation) and is applied with .kanbanTheme(_:). Card and column-header content is entirely yours via the cardContent and columnHeader view builders, so the theme never needs to know about your typography or layout.
- Optional SwiftData adapter —
AdvancedKanbanSwiftData(a separate
product) provides SwiftDataKanbanCard / SwiftDataKanbanColumn models and a KanbanStore that applies a KanbanMove to a ModelContext in one call. Not linked into the base AdvancedKanban library, so you're never forced into SwiftData if you don't want it.
Theming example
// The `KanbanBoard(...)` call is abbreviated here — see the full,
// copy-pasteable version in "Add a board in 3 steps" above. Only the
// `.kanbanTheme(_:)` modifier is the point of this snippet.
KanbanBoard(
columns: $columns,
cardContent: { task in Text(task.title).padding(8) },
columnHeader: { stage in Text(stage.name).font(.headline) }
)
.kanbanTheme(
KanbanTheme(
columnBackground: .gray.opacity(0.08),
cardBackground: .white,
cardBorder: .gray.opacity(0.2),
cardCornerRadius: 12,
cardSpacing: 8,
columnWidth: 280,
columnCornerRadius: 16,
wipLimitWarningColor: .orange,
dragGhostOpacity: 0.85,
dropAnimation: .spring(response: 0.35, dampingFraction: 0.8)
)
)KanbanTheme.default is used automatically if you don't apply one.
Example app
A runnable example lives in Example/. It demonstrates cross-column drag with a WIP limit, custom card content, theme switching, column collapse, keyboard reorder, and VoiceOver reorder — open Example/AdvancedKanbanExample.xcodeproj in Xcode and run it on macOS or an iOS/iPadOS simulator. Every view in the example also ships a #Preview, so you can inspect each theme/state combination directly in Xcode's canvas without running the app.
Two Xcode schemes are checked into the project — AdvancedKanbanExample (macOS) and AdvancedKanbanExample (iOS) — so opening the project gives a predictable, resizable native window on whichever platform you pick, rather than leaving Xcode to auto-select one.
Design spec
The full design rationale — protocol boundaries, drag-gesture state machine, keyboard/VoiceOver parity model, WIP limit semantics, and theming surface — is documented in docs/superpowers/specs/2026-08-19-advanced-kanban-design.md.
Installation
Swift Package Manager, via Xcode (File > Add Package Dependencies) or Package.swift:
dependencies: [
.package(url: "https://github.com/NerdSnipe-Inc/AdvancedKanban.git", from: "1.0.0")
]Then add the product(s) you need to your target:
.target(
name: "YourApp",
dependencies: [
.product(name: "AdvancedKanban", package: "AdvancedKanban"),
// Optional, only if you want the SwiftData persistence adapter:
.product(name: "AdvancedKanbanSwiftData", package: "AdvancedKanban"),
]
)Requires iOS 17+ / macOS 14+ and Swift 5.9+.
Also from NerdSnipe Inc
AdvancedKanban covers one component. If you're building the rest of the app around it, DesignFoundation Pro is a library of 55 production-ready SwiftUI screens and 30 SwiftUI UI blocks — AI Chat, CRM, Analytics, E-commerce, Social, Project Management, Onboarding, and more — built on the free, MIT-licensed DesignFoundation theming engine. Same theme token, every screen restyles.
License
AdvancedKanban is available under the MIT license. See LICENSE for the full text.
Support this project
AdvancedKanban is built and maintained by NerdSnipe Inc, a small independent studio in Ottawa. Sponsorship funds new board features and accessibility work.
- Sponsor on GitHub, from $5/month or a one-time amount
- More about what we fund
Package Metadata
Repository: nerdsnipe-inc/advancedkanban
Default branch: master
README: README.md