@bimetal/kanban-vanilla-components
v0.35.0
Published
Zero-framework Kanban binding: mountKanban() drives the canonical kanban controller with plain DOM. Peer of the kanban-{react,vue,svelte,angular}-components packages.
Readme
@bimetal/kanban-vanilla-components
The zero-framework Kanban board for BIMETAL — a thin binding over the
canonical @bimetal/kanban-headless controller, rendered
with plain DOM (no React/Vue/Svelte/Angular). A peer of the
kanban-{react,vue,svelte,angular}-components packages and behaviourally
identical to them. Every interaction decision (drag thresholds, drop indices,
WIP rejection, input policy, undo) lives in the headless controller; this
package owns only the DOM: hit-testing pointer drags, normalising keyboard
events, and reconciling the rendered tree to the controller snapshot.
Features
- Real drag-and-drop — pointer drag across and within columns, with a live drop-gap indicator. No per-card move buttons.
- Keyboard a11y — Space to pick up, arrows to move (←/→ across
columns, ↑/↓ within), Space/Enter to drop, Esc
to cancel;
aria-grabbedreflects the held card. - Columns — add, rename inline, reorder, delete (cards cascade), per-column WIP limits that reject over-limit moves as an undo toast.
- Cards — title, description, labels; custom card bodies via
renderCardwhile the drag/focus wrapper stays owned by the mount. - Filter, undo, theming — text filter, one-click undo, light/dark token set shared with the framework packages.
Usage
import { mountKanban } from '@bimetal/kanban-vanilla-components';
import '@bimetal/kanban-vanilla-components/styles';
import { createKanbanStore, createBoard } from '@bimetal/kanban-data';
const store = createKanbanStore();
await store.dispatch(createBoard({ id: 'b1', columns: [/* … */], cards: {} }));
const handle = mountKanban(document.getElementById('app')!, {
store,
boardId: 'b1',
darkMode: false,
showFilter: true,
// renderCard: a string is rendered as TEXT (never HTML); for rich content
// build a node: renderCard: (card) => { const n = document.createElement('strong'); n.textContent = card.title; return n; },
});
// later
handle.destroy();mountKanban(target, options) returns a handle with getController() and
destroy() (unsubscribe, remove window listeners, destroy the controller, clear
the DOM).
Options
| option | type | default | notes |
| ------------ | ------------------------------------------ | ------- | ------------------------------------------------------------ |
| store | KanbanStore | — | immutable after mount |
| boardId | string | — | immutable after mount |
| config | KanbanConfigInput | — | locale overrides |
| darkMode | boolean | false | sets data-theme="dark" on the root |
| showFilter | boolean | true | renders the text filter |
| renderCard | (card) => string \| HTMLElement | — | custom card body; the drag/focus wrapper stays mount-owned |
| onError | (err: unknown) => void | — | non-domain error channel (see the controller error contract) |
License
Apache License 2.0
