# `PhiaUi.Components.KanbanBoard`
[🔗](https://github.com/charlenopires/PhiaUI/blob/v0.1.17/lib/phia_ui/components/data/kanban_board.ex#L1)

Kanban board component for PhiaUI.

Renders a horizontal workflow board composed of named columns and draggable
task cards. The layout is CSS-only; drag-and-drop reordering is provided by
the optional `PhiaKanban` vanilla-JS hook.

## When to use

Use `KanbanBoard` whenever you need a multi-stage workflow visualisation with
discrete status columns — project management, recruitment pipelines, support
ticket queues, content-approval workflows, etc.

## Anatomy

| Component       | Element | Purpose                                         |
|-----------------|---------|--------------------------------------------------|
| `kanban_board/1`  | `div`   | Horizontal scroll container for all columns     |
| `kanban_column/1` | `div`   | A single workflow stage (label + optional count)|
| `kanban_card/1`   | `li`    | An individual task card with slots              |

## Priority levels

| Value      | Left-border colour                |
|------------|----------------------------------|
| `critical` | `border-l-destructive` (red)     |
| `high`     | `border-l-orange-500` (orange)   |
| `medium`   | `border-l-yellow-500` (yellow)   |
| `low`      | `border-l-muted-foreground/40`   |

## Minimal example

    <.kanban_board id="project-board">
      <.kanban_column id="col-todo" label="To Do" count={length(@todo_cards)}>
        <.kanban_card
          :for={card <- @todo_cards}
          id={"card-#{card.id}"}
          title={card.title}
          priority={card.priority}
        />
      </.kanban_column>
    </.kanban_board>

## Full project-management board with LiveView streams

LiveView streams keep DOM diffing minimal — only changed cards are patched,
not the entire column.

    <.kanban_board id="pm-board" phx-hook="PhiaKanban" data-on-move="card_moved">
      <.kanban_column id="col-backlog" label="Backlog" count={@backlog_count}>
        <.kanban_card
          :for={{dom_id, card} <- @streams.backlog}
          id={dom_id}
          title={card.title}
          priority={card.priority}
          phx-click="open_card"
          phx-value-id={card.id}
        >
          <:avatar>
            <.avatar size="xs">
              <.avatar_image src={card.assignee_avatar} />
              <.avatar_fallback name={card.assignee_name} />
            </.avatar>
          </:avatar>
          <:tags>
            <.badge :for={label <- card.labels} variant="secondary" size="sm">
              {label}
            </.badge>
          </:tags>
          <:footer>
            <.icon name="calendar" size={:xs} />
            <span>{card.due_date}</span>
            <.icon name="message-square" size={:xs} class="ml-auto" />
            <span>{card.comment_count}</span>
          </:footer>
        </.kanban_card>
      </.kanban_column>

      <.kanban_column id="col-in-progress" label="In Progress" count={@in_progress_count}>
        <%!-- ... --%>
      </.kanban_column>

      <.kanban_column id="col-done" label="Done" count={@done_count}>
        <%!-- ... --%>
      </.kanban_column>
    </.kanban_board>

## Drag-and-drop setup (optional)

The board works without the hook — cards are static server-rendered items.
Add `phx-hook="PhiaKanban"` to `kanban_board/1` to enable drag-and-drop
reordering. The hook emits a `push_event("phx:card_moved", %{id, from, to, index})`
on every successful drop.

    # app.js
    import PhiaKanban from "./hooks/kanban"
    let liveSocket = new LiveSocket("/live", Socket, {
      hooks: { PhiaKanban }
    })

    # LiveView handler
    def handle_event("card_moved", %{"id" => id, "from" => from, "to" => to, "index" => idx}, socket) do
      # Update the card's column and position in your database
      {:noreply, socket}
    end

# `kanban_board`

Renders the kanban board root container.

All `kanban_column/1` components go inside. The board overflows horizontally
on narrow screens so every column remains accessible without horizontal
viewport scrolling that would break the page layout.

## Example

    <.kanban_board id="sales-pipeline">
      <.kanban_column id="col-lead" label="Lead" count={12}>
        ...
      </.kanban_column>
      <.kanban_column id="col-qualified" label="Qualified" count={5}>
        ...
      </.kanban_column>
    </.kanban_board>

## Attributes

* `id` (`:string`) (required) - DOM id for the board element. Required for LiveView streams and the PhiaKanban hook.
* `class` (`:string`) - Additional CSS classes for the board container. Defaults to `nil`.
* Global attributes are accepted. HTML attributes forwarded to the root element.
  Use `phx-hook="PhiaKanban"` to enable drag-and-drop reordering.
  Use `data-on-move` to specify the LiveView event name for card moves.
 Supports all globals plus: `["phx-hook", "data-on-move"]`.
## Slots

* `inner_block` (required) - `kanban_column/1` children.

# `kanban_card`

Renders a single kanban task card.

Cards are `<li>` elements inside the column's `<ol>`, which preserves
correct document semantics for ordered task lists.

The priority-coloured left border gives a quick visual signal without
requiring team members to read each card individually.

## Example — full card with all slots

    <.kanban_card
      id={"card-#{task.id}"}
      title={task.title}
      priority={task.priority}
      phx-click="open_task"
      phx-value-id={task.id}
    >
      <:avatar>
        <.avatar size="xs">
          <.avatar_image src={task.assignee.avatar_url} />
          <.avatar_fallback name={task.assignee.name} />
        </.avatar>
      </:avatar>
      <:tags>
        <.badge :for={label <- task.labels} variant="secondary" size="sm">
          {label.name}
        </.badge>
      </:tags>
      <:footer>
        <.icon name="calendar" size={:xs} />
        <span>Due {task.due_date}</span>
      </:footer>
    </.kanban_card>

## Attributes

* `id` (`:string`) (required) - DOM id for the card element. Required for LiveView streams (`dom_id` from stream).
* `title` (`:string`) (required) - Card title — the task or item name.
* `priority` (`:string`) - Priority level. Controls the left-border accent colour:
  - `critical` — red (destructive)
  - `high`     — orange
  - `medium`   — yellow
  - `low`      — muted

  Defaults to `"medium"`. Must be one of `"critical"`, `"high"`, `"medium"`, or `"low"`.
* `class` (`:string`) - Additional CSS classes for the card. Defaults to `nil`.
* Global attributes are accepted. HTML attributes forwarded to the `<li>` card element.
  Add `phx-click="open_card" phx-value-id={card.id}` to make cards clickable.
  The PhiaKanban hook sets `draggable="true"` automatically when enabled.
 Supports all globals plus: `["phx-click", "phx-value-id", "draggable"]`.
## Slots

* `avatar` - Optional avatar or `avatar_group/1` for assignees.
  Rendered in the top-right of the card header.

* `tags` - Optional tag / badge row rendered below the title.
  Use `badge/1` components with `variant="secondary"`.

* `footer` - Optional footer row for metadata such as due dates, comment counts, or
  story-point estimates. Content is rendered at `text-xs text-muted-foreground`.

# `kanban_column`

Renders a single kanban workflow column.

Each column has a fixed width of `w-64` (256 px) and does not shrink, which
ensures consistent column widths regardless of card content. The count badge
helps teams see at a glance whether a stage has become a bottleneck.

## Example

    <.kanban_column id="col-review" label="In Review" count={@review_count}>
      <.kanban_card
        :for={{dom_id, card} <- @streams.review}
        id={dom_id}
        title={card.title}
        priority={card.priority}
      />
    </.kanban_column>

## Attributes

* `id` (`:string`) (required) - DOM id for the column. Required for the PhiaKanban hook to identify drop zones.
* `label` (`:string`) (required) - Column heading for the workflow stage, e.g. "To Do", "In Progress", "Done".
* `count` (`:integer`) - Optional item count displayed as a badge beside the label.
  Useful for at-a-glance capacity monitoring.
  Pass `nil` to omit the badge.

  Defaults to `nil`.
* `class` (`:string`) - Additional CSS classes for the column wrapper. Defaults to `nil`.
* Global attributes are accepted. HTML attributes forwarded to the column div (e.g. `data-column-id` for the hook).
## Slots

* `inner_block` (required) - `kanban_card/1` children.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
