Tables
Responsive list pages with search, period filters, mobile card collapse, and tag helper tables.
Quotes list page
A realistic list page combining search, period filter, mobile cards, desktop table, load more, and empty state. On mobile (<xl), data renders as stacked cards. On desktop (xl+), data renders as a standard table.
| Reference | Address | Client | Status | Fee total | Actions |
|---|---|---|---|---|---|
| KQ-001234 | 12 Elm Street, London, SW1A 1AA | James Wilson | Accepted | £1,250.00 | View |
| KQ-001235 | 4 Oak Avenue, Manchester, M1 2AB | Sarah Chen | New | £980.00 | View |
| KQ-001236 | 7 Birch Lane, Birmingham, B2 4CD | Michael Brown | Expired | £1,100.00 | View |
| KQ-001237 | 22 Pine Road, Leeds, LS1 5EF | Emma Taylor | Cancelled | £750.00 | View |
| KQ-001238 | 9 Willow Close, Bristol, BS1 6GH | Olivia Martinez | Approved | £1,450.00 | View |
<!-- Toolbar: Search + Period filter -->
<div class="flex flex-col sm:flex-row gap-3 p-4">
<div class="relative flex-1 max-w-sm">
<div class="absolute inset-y-0 start-0 flex items-center ps-3
pointer-events-none text-gray-400 dark:text-gray-500">
<svg ...>
<circle cx="11" cy="11" r="8"></circle>
<path d="m21 21-4.3-4.3"></path>
</svg>
</div>
<input type="search" placeholder="Search..."
class="block w-full ps-9 pe-3 py-2.5 bg-white dark:bg-gray-700
border border-gray-200 dark:border-gray-600 ..."/>
</div>
<select asp-for="Input.Period">
<option value="7d">Last 7 days</option>
<option value="30d">Last 30 days</option>
<option value="3m">Last 3 months</option>
<option value="12m">Last 12 months</option>
<option value="all">All time</option>
</select>
</div>
<!-- Mobile cards (<xl) -->
<div class="xl:hidden border-t border-gray-200 dark:border-gray-700">
@foreach (var quote in Model.Quotes)
{
<div x-data
x-on:click="..."
class="px-4 py-4 sm:px-6 border-b border-gray-100 dark:border-gray-700
hover:bg-gray-100 dark:hover:bg-gray-700/50 transition-colors cursor-pointer">
<span class="float-right ...">@quote.FeeTotal</span>
<div class="flex items-center gap-2 min-w-0">
<a href="..." data-primary class="font-mono ...">@quote.DisplayReference</a>
<span koala-badge="Success">Accepted</span>
</div>
<div class="text-gray-500 dark:text-gray-400 mt-1">@quote.Address</div>
<div class="text-gray-500 dark:text-gray-400 mt-1">@quote.ClientName</div>
</div>
}
</div>
<!-- Desktop table (xl+) -->
<div class="hidden xl:block">
<div class="overflow-x-auto">
<table class="w-full">
<thead>
<tr>
<th koala-th>Reference</th>
<th koala-th>Address</th>
<th koala-th>Client</th>
<th koala-th>Status</th>
<th koala-th class="text-right">Fee total</th>
<th koala-th><span class="sr-only">Actions</span></th>
</tr>
</thead>
<tbody>
<tr koala-tr>
<td koala-td koala-td-primary>KQ-001234</td>
<td koala-td>12 Elm Street, London</td>
<td koala-td>James Wilson</td>
<td koala-td><span koala-badge="Success">Accepted</span></td>
<td koala-td class="text-right">£1,250.00</td>
<td koala-td><a href="...">View</a></td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- Load more -->
<div koala-load-more="quote-rows" koala-load-more-url="@loadMoreUrl"></div>
Empty state
Shown when a search or filter returns zero results. Replace the cards/table with
koala-empty-state.
No quotes match your search.
@if (Model.Quotes.Count == 0)
{
<div koala-empty-state>No quotes match your search.</div>
}
else
{
<!-- Cards + table markup -->
}
Finance table
A simple fees table that does not collapse to cards on mobile. Uses
overflow-x-auto
with min-w-[640px]
for horizontal scrolling. Custom padding and width classes are used instead of the standard
koala-th /
koala-td tag helpers.
| Description | Net | VAT | Disbursement | Gross |
|---|---|---|---|---|
| Legal fee | £500.00 | £100.00 | — | £600.00 |
| Search pack | — | — | £300.00 | £300.00 |
| Land Registry fee | — | — | £270.00 | £270.00 |
| Stamp duty | — | — | £2,500.00 | £2,500.00 |
| Total | £500.00 | £100.00 | £3,070.00 | £3,670.00 |
<!-- Finance tables use custom padding (ps-4 pe-2) and width classes -->
<!-- Do NOT use koala-th / koala-td tag helpers for these -->
<div class="overflow-x-auto">
<table class="w-full min-w-[640px]">
<thead>
<tr>
<th class="w-[35%] ps-4 pe-2 py-3 text-left text-sm font-bold uppercase
tracking-wider text-gray-700 dark:text-gray-200
bg-gray-50 dark:bg-gray-800/50 whitespace-nowrap"
scope="col">Description</th>
<th class="w-[20%] px-2 py-3 text-right ..." scope="col">Net</th>
<th class="w-[15%] px-2 py-3 text-right ..." scope="col">VAT</th>
<th class="w-[15%] px-2 py-3 text-right ..." scope="col">Disbursement</th>
<th class="w-[15%] ps-2 pe-4 py-3 text-right ..." scope="col">Gross</th>
</tr>
</thead>
<tbody>
<tr class="border-b border-gray-100 dark:border-gray-700">
<td class="ps-4 pe-2 py-3.5 font-medium text-gray-900 dark:text-white">Legal fee</td>
<td class="px-2 py-3.5 text-right text-gray-500 dark:text-gray-400">£500.00</td>
<td class="px-2 py-3.5 text-right ...">£100.00</td>
<td class="px-2 py-3.5 text-right ...">—</td>
<td class="ps-2 pe-4 py-3.5 text-right font-medium text-gray-900 dark:text-white">£600.00</td>
</tr>
<!-- Total row -->
<tr class="bg-gray-50 dark:bg-gray-800/50">
<td class="ps-4 pe-2 py-3.5 font-bold text-gray-900 dark:text-white">Total</td>
<td class="px-2 py-3.5 text-right font-bold ...">£500.00</td>
...
</tr>
</tbody>
</table>
</div>
Tab count pills
Use koala-tab-pill for count badges in tab navigation.
<span koala-tab-pill>42</span>
Output classes reference
Classes applied by each tag helper.
| Tag helper | Output classes |
|---|---|
| koala-th | px-4 py-3 text-sm font-bold uppercase tracking-wider text-gray-700 dark:text-gray-200 bg-gray-50 dark:bg-gray-800/50 whitespace-nowrap + scope="col" |
| koala-td | px-4 py-3.5 text-gray-500 dark:text-gray-400 whitespace-nowrap |
| koala-td-primary | px-4 py-3.5 font-medium text-gray-900 dark:text-white whitespace-nowrap |
| koala-tr | even:bg-gray-50 dark:even:bg-gray-800/50 border-b border-gray-100 dark:border-gray-700 hover:bg-brand-softer dark:hover:bg-gray-700 transition-colors + x-data + click handler |