Koala logo Design
No matches for “
↑↓ navigate open Esc close
Components List

List

The generic slotted list-row primitive — shared chrome for list grids whose cells are bespoke. It owns the desktop column header, the rows container, and the clickable row card with its mobile-stacked vs desktop-grid switch; every cell stays page-authored. Where list table + list card render the fixed quote/transaction columns, this family can represent any team, clients, organisations, or branches row shape.

<koala-list>
@{ const string DesktopGrid = "grid grid-cols-[minmax(200px,1.5fr)_minmax(220px,2fr)_minmax(120px,1fr)] gap-4 items-center"; }

<koala-list-header grid-class="@DesktopGrid">
    <div>Name</div>
    <div>Email</div>
    <div>Role</div>
</koala-list-header>
<koala-list-rows rows-id="team-rows">
    @foreach (var member in Model.Team)
    {
        <koala-list-row href="@ViewUser.Route(member.Id)" grid-class="@DesktopGrid">
            <koala-list-mobile>...stacked cells...</koala-list-mobile>
            <koala-list-desktop>...one <div> per header column...</koala-list-desktop>
        </koala-list-row>
    }
</koala-list-rows>

The most-used shape — a team list. Resize the window to see each row flip between a stacked card and a horizontal grid at sm. The page keeps a single const string DesktopGrid and passes it to the header and every row, so the columns always line up and Tailwind compiles the literal.

Reach for this family when the row cells are bespoke — team, clients, organisations, users, releases, branches. Quote and transaction lists have a fixed column set and use list table + list card instead.

3 variants
Breakpoint Sm (default)
breakpoint="Sm"
Header and grid appear from sm (640px). The default for three-or-four-column grids.
Breakpoint Lg
breakpoint="Lg"
Rows stay stacked until lg (1024px) — for wide, many-column grids that would crush at sm. Set the same breakpoint on the header and every row.
elena.kowalski@hartleyshaw.co.uk
Delegate row
delegate
Renders a <div> instead of an <a> for rows with their own nested controls (an action menu, inline buttons), which can't legally nest inside an anchor. The whole surface routes to the inner a[data-primary] link; clicks on nested anchors/buttons are left alone. href is ignored.
<koala-list-row delegate grid-class="@DesktopGrid">
    <koala-list-desktop>
        <div class="min-w-0 flex items-center gap-2">
            <a data-primary href="@ViewUser.Route(member.Id)" x-target.push="main"
               class="font-semibold text-on-surface hover:underline truncate">@member.DisplayName</a>
        </div>
        ...
        <div class="flex justify-end">
            <button type="button" koala-icon-button="Neutral" koala-icon-button-variant="Ghost" class="w-8 h-8">
                <koala-icon name="MoreVertical" />
            </button>
        </div>
    </koala-list-desktop>
</koala-list-row>
1 state
Default
The row is a koala-card anchor. Hover lifts it to shadow-floating; click swaps #main via x-target.push (no full reload). Hover this row to see the lift.

Delegate rows add a keyboard state: the <div> is focusable (tabindex="0"), Enter follows the a[data-primary] link, and Cmd/Ctrl-click opens it in a new tab.

8 attributes
Element Attribute Notes
koala-list-header grid-class Full grid class string for the desktop header row — the same literal grid grid-cols-[…] … each row uses, so header and rows line up. Authored in the .cshtml so Tailwind compiles it.
koala-list-header breakpoint Sm (default) or Lg. Breakpoint at which the header appears (hidden below).
koala-list-rows rows-id Optional id on the rows container. Set when the page uses Alpine-AJAX x-merge="append" for load-more batches — point koala-load-more at the same id. The container always carries the space-y-3 gap.
koala-list-row href Destination the row navigates to (swaps #main via x-target.push). Ignored when delegate is set.
koala-list-row grid-class The shared desktop grid literal — pass the same string as the header.
koala-list-row breakpoint Sm (default) or Lg. Where the row flips from stacked to grid. Both slots read it from the row, so set it once per row (matching the header).
koala-list-row delegate Render a click-delegating <div> instead of an <a>, for rows with nested interactive controls. Navigation comes from the row's inner a[data-primary] link.
koala-list-mobile class Extra classes merged after the visibility class (e.g. flex items-center gap-3).
koala-list-desktop No attributes. Reads the breakpoint and grid class from the parent <koala-list-row> and renders hidden {bp}:grid {grid-class}.
Do Reach for the family when the row cells are bespoke — team, clients, organisations, branches. Every cell stays page-authored, so any row shape fits without a per-column enum.
<a koala-card class="block hover:...">
  <div class="sm:hidden">...</div>
  <div class="hidden sm:grid ...">...</div>
</a>
Don't Don't hand-roll the dual layout — the hidden sm:grid / sm:hidden pair and the clickable card anchor are exactly what the row owns. And don't use it where list table + list card already fit: quote and transaction lists have a fixed, closed column set.

Mobile & desktop slots

Every <koala-list-row> authors its cells twice — that's the dual-render contract. <koala-list-mobile> is the stacked layout, hidden at/above the row's breakpoint; <koala-list-desktop> is hidden below it and flips to a grid using the row's grid-class. Both slots read the breakpoint and grid spec from the parent row, so they carry no configuration of their own — the desktop slot just needs one <div> per column of the shared grid, in header order.

<koala-list-row href="@viewUrl" grid-class="@DesktopGrid">
    @* Below the breakpoint — stacked. Extra classes merge after the visibility class. *@
    <koala-list-mobile>
        <div class="flex items-center gap-2 min-w-0">...</div>
        <div class="mt-1 text-on-surface-muted truncate">...</div>
    </koala-list-mobile>
    @* At/above the breakpoint — one <div> per column of the shared grid. *@
    <koala-list-desktop>
        <div>...</div>
        <div>...</div>
        <div>...</div>
    </koala-list-desktop>
</koala-list-row>

The two slots exist so each layout can be honest about its shape — mobile stacks identity, detail, and badges vertically; desktop places one cell per column. Don't try to force one markup tree to serve both with utility gymnastics; author each slot for its layout.