Swimlane

Horizontal grouping on a Kanban board.

Assignee: Priya Nair

To do 2 items

  • Draft onboarding flow PN
  • Audit empty states PN

In progress 1 item

  • Ship notification prefs PN

html

<section class="swimlane" aria-labelledby="swimlane-heading" style="--accent: #D9C8F0;">
  <h3 id="swimlane-heading" class="swimlane__heading">Assignee: Priya Nair</h3>
  <div class="swimlane__scroll">
    <div class="swimlane__strip">
      <section class="swimlane__column" aria-labelledby="swimlane-col-todo">
        <h4 id="swimlane-col-todo" class="swimlane__column-title">To do <span class="swimlane__count">2 items</span></h4>
        <ul class="swimlane__cards">
          <li class="swimlane__card" draggable="true">
            <span class="swimlane__card-title">Draft onboarding flow</span>
            <span class="swimlane__card-avatar">PN</span>
            <button type="button" class="swimlane__move">Move to In progress</button>
          </li>
          <li class="swimlane__card" draggable="true">
            <span class="swimlane__card-title">Audit empty states</span>
            <span class="swimlane__card-avatar">PN</span>
            <button type="button" class="swimlane__move">Move to In progress</button>
          </li>
        </ul>
      </section>
      <section class="swimlane__column" aria-labelledby="swimlane-col-progress">
        <h4 id="swimlane-col-progress" class="swimlane__column-title">In progress <span class="swimlane__count">1 item</span></h4>
        <ul class="swimlane__cards">
          <li class="swimlane__card" draggable="true">
            <span class="swimlane__card-title">Ship notification prefs</span>
            <span class="swimlane__card-avatar">PN</span>
            <button type="button" class="swimlane__move">Move to Done</button>
          </li>
        </ul>
      </section>
    </div>
  </div>
</section>
<style>
.swimlane { font-family: system-ui, sans-serif; color: #241430; background: #FAF7F2; padding: 16px; border-radius: 10px; max-width: 660px; box-sizing: border-box; }
.swimlane__heading { margin: 0 0 12px; font-size: 15px; font-weight: 700; }
.swimlane__scroll { overflow-x: auto; padding-bottom: 4px; }
.swimlane__strip { display: flex; gap: 16px; min-width: max-content; }
.swimlane__strip--compact { gap: 8px; }
.swimlane__column { width: 220px; flex: 0 0 auto; background: #24143008; border-radius: 8px; padding: 10px; box-sizing: border-box; }
.swimlane__strip--compact .swimlane__column { width: 180px; padding: 6px; }
.swimlane__column-title { margin: 0 0 8px; font-size: 13px; font-weight: 600; display: flex; justify-content: space-between; align-items: center; }
.swimlane__count { font-weight: 500; font-size: 11px; color: #241430aa; }
.swimlane__cards { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.swimlane__card { background: #FAF7F2; border: 1px solid #24143020; border-radius: 6px; padding: 8px; display: flex; flex-wrap: wrap; align-items: center; gap: 6px; font-size: 12.5px; }
.swimlane__card-title { flex: 1 1 auto; }
.swimlane__card-avatar { width: 22px; height: 22px; border-radius: 50%; background: var(--accent); display: inline-flex; align-items: center; justify-content: center; font-size: 10px; font-weight: 700; color: #241430; }
.swimlane__move { flex: 0 0 100%; font-size: 11px; border: 1px solid #24143040; background: transparent; border-radius: 6px; padding: 4px 6px; cursor: pointer; color: #241430; }
.swimlane__move:hover, .swimlane__move:focus-visible { background: #24143012; outline: 2px solid var(--accent); outline-offset: 1px; }
</style>

tailwind

<section class="swimlane-tw font-sans text-[#241430] bg-[#FAF7F2] p-4 rounded-[10px] max-w-[660px] box-border" aria-labelledby="swimlane-tw-heading" style="--accent: #D9C8F0;">
  <h3 id="swimlane-tw-heading" class="m-0 mb-3 text-[15px] font-bold">Assignee: Priya Nair</h3>
  <div class="overflow-x-auto pb-1">
    <div class="swimlane-tw__strip flex gap-4" style="min-width: max-content;">
      <section class="swimlane-tw__column w-[220px] flex-none bg-[#24143008] rounded-lg p-2.5 box-border" aria-labelledby="swimlane-tw-col-todo">
        <h4 id="swimlane-tw-col-todo" class="m-0 mb-2 text-[13px] font-semibold flex justify-between items-center">To do <span class="font-medium text-[11px] text-[#241430aa]">2 items</span></h4>
        <ul class="list-none m-0 p-0 flex flex-col gap-2">
          <li class="flex flex-wrap items-center gap-1.5 bg-[#FAF7F2] border border-[#24143020] rounded-md p-2 text-[12.5px]" draggable="true">
            <span class="flex-1">Draft onboarding flow</span>
            <span class="w-[22px] h-[22px] rounded-full inline-flex items-center justify-center text-[10px] font-bold" style="background: var(--accent);">PN</span>
            <button type="button" class="swimlane-tw__move flex-none w-full text-[11px] border border-[#24143040] bg-transparent rounded-md px-1.5 py-1 cursor-pointer text-[#241430]">Move to In progress</button>
          </li>
          <li class="flex flex-wrap items-center gap-1.5 bg-[#FAF7F2] border border-[#24143020] rounded-md p-2 text-[12.5px]" draggable="true">
            <span class="flex-1">Audit empty states</span>
            <span class="w-[22px] h-[22px] rounded-full inline-flex items-center justify-center text-[10px] font-bold" style="background: var(--accent);">PN</span>
            <button type="button" class="swimlane-tw__move flex-none w-full text-[11px] border border-[#24143040] bg-transparent rounded-md px-1.5 py-1 cursor-pointer text-[#241430]">Move to In progress</button>
          </li>
        </ul>
      </section>
      <section class="swimlane-tw__column w-[220px] flex-none bg-[#24143008] rounded-lg p-2.5 box-border" aria-labelledby="swimlane-tw-col-progress">
        <h4 id="swimlane-tw-col-progress" class="m-0 mb-2 text-[13px] font-semibold flex justify-between items-center">In progress <span class="font-medium text-[11px] text-[#241430aa]">1 item</span></h4>
        <ul class="list-none m-0 p-0 flex flex-col gap-2">
          <li class="flex flex-wrap items-center gap-1.5 bg-[#FAF7F2] border border-[#24143020] rounded-md p-2 text-[12.5px]" draggable="true">
            <span class="flex-1">Ship notification prefs</span>
            <span class="w-[22px] h-[22px] rounded-full inline-flex items-center justify-center text-[10px] font-bold" style="background: var(--accent);">PN</span>
            <button type="button" class="swimlane-tw__move flex-none w-full text-[11px] border border-[#24143040] bg-transparent rounded-md px-1.5 py-1 cursor-pointer text-[#241430]">Move to Done</button>
          </li>
        </ul>
      </section>
    </div>
  </div>
</section>
<style>
.swimlane-tw__strip--compact { gap: 8px; }
.swimlane-tw__strip--compact .swimlane-tw__column { width: 180px; padding: 6px; }
.swimlane-tw__move:hover, .swimlane-tw__move:focus-visible { background: #24143012; outline: 2px solid var(--accent); outline-offset: 1px; }
</style>

react

export function Swimlane({
  groupBy = "Assignee",
  laneName = "Priya Nair",
  accent = "#D9C8F0",
  showCount = true,
  compact = false,
}) {
  const columnStyle = { width: compact ? 180 : 220, flex: "0 0 auto", background: "#24143008", borderRadius: 8, padding: compact ? 6 : 10, boxSizing: "border-box" };
  const cardStyle = { background: "#FAF7F2", border: "1px solid #24143020", borderRadius: 6, padding: 8, display: "flex", flexWrap: "wrap", alignItems: "center", gap: 6, fontSize: 12.5 };
  const avatarStyle = { width: 22, height: 22, borderRadius: "50%", background: accent, display: "inline-flex", alignItems: "center", justifyContent: "center", fontSize: 10, fontWeight: 700, color: "#241430" };
  const moveBtnStyle = { flex: "0 0 100%", fontSize: 11, border: "1px solid #24143040", background: "transparent", borderRadius: 6, padding: "4px 6px", cursor: "pointer", color: "#241430" };
  return (
    <section aria-labelledby="swimlane-heading" style={{ fontFamily: "system-ui, sans-serif", color: "#241430",
      background: "#FAF7F2", padding: 16, borderRadius: 10, maxWidth: 660, boxSizing: "border-box" }}>
      <h3 id="swimlane-heading" style={{ margin: "0 0 12px", fontSize: 15, fontWeight: 700 }}>{groupBy}: {laneName}</h3>
      <div style={{ overflowX: "auto", paddingBottom: 4 }}>
        <div style={{ display: "flex", gap: compact ? 8 : 16, minWidth: "max-content" }}>
          <section aria-labelledby="swimlane-col-todo" style={columnStyle}>
            <h4 id="swimlane-col-todo" style={{ margin: "0 0 8px", fontSize: 13, fontWeight: 600, display: "flex", justifyContent: "space-between", alignItems: "center" }}>
              To do {showCount && <span style={{ fontWeight: 500, fontSize: 11, color: "#241430aa" }}>2 items</span>}
            </h4>
            <ul style={{ listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 8 }}>
              <li style={cardStyle} draggable="true">
                <span style={{ flex: "1 1 auto" }}>Draft onboarding flow</span>
                <span style={avatarStyle}>PN</span>
                <button type="button" style={moveBtnStyle}>Move to In progress</button>
              </li>
              <li style={cardStyle} draggable="true">
                <span style={{ flex: "1 1 auto" }}>Audit empty states</span>
                <span style={avatarStyle}>PN</span>
                <button type="button" style={moveBtnStyle}>Move to In progress</button>
              </li>
            </ul>
          </section>
          <section aria-labelledby="swimlane-col-progress" style={columnStyle}>
            <h4 id="swimlane-col-progress" style={{ margin: "0 0 8px", fontSize: 13, fontWeight: 600, display: "flex", justifyContent: "space-between", alignItems: "center" }}>
              In progress {showCount && <span style={{ fontWeight: 500, fontSize: 11, color: "#241430aa" }}>1 item</span>}
            </h4>
            <ul style={{ listStyle: "none", margin: 0, padding: 0, display: "flex", flexDirection: "column", gap: 8 }}>
              <li style={cardStyle} draggable="true">
                <span style={{ flex: "1 1 auto" }}>Ship notification prefs</span>
                <span style={avatarStyle}>PN</span>
                <button type="button" style={moveBtnStyle}>Move to Done</button>
              </li>
            </ul>
          </section>
        </div>
      </div>
    </section>
  );
}