Kanban Column
Overview
A two-column kanban: click a card to move it to the other column. FLIP records the before and after positions and tweens with transform only, so nothing jumps.
Plain HTML, CSS and a little vanilla JS, with no framework dependency. Copy the prompt into Claude Code, Cursor, Trae or Codex and the model adds Kanban Column to your project in your colors.
Where to use it
Dashboards, data tables, chart cards, comparison tables and status panels.
Install
With Builder, install it with the 8pt CLI or call it directly from an editor connected to 8pt MCP.
$ npm i -g @8pt-dev/cli && 8pt add kanban-column
mcp › Use 8pt MCP to call get_component("kanban-column")
Code
Source for Kanban Column. Motion uses only transform and opacity and respects the Reduce motion setting.
<div class="x-kb">
<section class="x-kb__col" data-col="doing"><header>In progress <em>3</em></header>
<button type="button" class="x-kb__card" data-tag="Design"><i></i>Home hero redesign</button>
<button type="button" class="x-kb__card" data-tag="Frontend"><i></i>Pricing page toggle animation</button>
<button type="button" class="x-kb__card" data-tag="Docs"><i></i>Add MCP examples</button>
</section>
<section class="x-kb__col" data-col="done"><header>Completed <em>1</em></header>
<button type="button" class="x-kb__card" data-tag="Frontend"><i></i>Dark mode variables</button>
</section>
</div>.x-kb{display:grid;grid-template-columns:1fr 1fr;gap:10px;width:min(340px,100%);color:var(--d-fg,#fff)}
.x-kb__col{display:flex;flex-direction:column;gap:6px;min-height:200px;padding:8px;border-radius:14px;background:color-mix(in srgb,var(--d-card,#14141c) 70%,transparent);border:1px solid var(--d-line,rgba(255,255,255,.1))}
.x-kb__col header{display:flex;align-items:center;justify-content:space-between;padding:2px 4px 6px;font:600 12px/1 var(--d-font,system-ui,sans-serif);color:var(--d-muted,#9b9ba8)}
.x-kb__col header em{font-style:normal;min-width:20px;padding:3px 6px;border-radius:999px;background:var(--d-line,rgba(255,255,255,.1));text-align:center;font-variant-numeric:tabular-nums}
.x-kb__card{position:relative;display:grid;gap:7px;padding:9px 10px;border-radius:10px;border:1px solid var(--d-line,rgba(255,255,255,.1));background:var(--d-card,#14141c);color:inherit;font:500 12.5px/1.35 var(--d-font,system-ui,sans-serif);text-align:left;cursor:pointer;box-shadow:0 6px 14px -10px rgba(0,0,0,.6);transition:box-shadow .2s;will-change:transform}
.x-kb__card::before{content:attr(data-tag);justify-self:start;padding:3px 6px;border-radius:5px;font:600 10px/1 var(--d-font,system-ui,sans-serif);color:var(--d-accent,#4D74FF);background:color-mix(in srgb,var(--d-accent,#4D74FF) 15%,transparent)}
.x-kb__card:hover{box-shadow:0 10px 22px -10px rgba(0,0,0,.7)}
.x-kb__card i{display:none}
[data-col=done] .x-kb__card{color:var(--d-muted,#9b9ba8);text-decoration:line-through;text-decoration-color:color-mix(in srgb,var(--d-muted,#9b9ba8) 60%,transparent)}
[data-col=done] .x-kb__card::before{color:#3dd68c;background:rgba(61,214,140,.14)}const init = (root) => {
const cols = [...root.querySelectorAll('.x-kb__col')];
const count = () => cols.forEach(c => c.querySelector('em').textContent = c.querySelectorAll('.x-kb__card').length);
const reduce = matchMedia('(prefers-reduced-motion: reduce)').matches;
const move = (card) => {
const cards = [...root.querySelectorAll('.x-kb__card')], first = new Map(cards.map(c => [c, c.getBoundingClientRect()]));
const to = card.closest('.x-kb__col') === cols[0] ? cols[1] : cols[0];
to.insertBefore(card, to.children[1] || null); count();
if (reduce) return;
cards.forEach(c => { const a = first.get(c), b = c.getBoundingClientRect(), dx = a.left - b.left, dy = a.top - b.top; if (!dx && !dy) return;
c.animate([{ transform: `translate(${dx}px, ${dy}px)` + (c === card ? ' rotate(-3deg) scale(1.04)' : '') }, { transform: 'none' }], { duration: 480, easing: 'cubic-bezier(.2,.8,.2,1)' }); });
};
…Subscribe to Builder to see the full source.See pricing