Table
A card-style, horizontally scrollable container and ready-made table styles for data tables. You write your own table tag; the ui-table class gives the look of headers, cells, rows and the totals row.
Basic usage
Put the table inside acun:table and give the table tag the ui-table class. The container frames the table like a white card and scrolls horizontally when the columns do not fit. Cells are single-line by default.
<acun:table>
<table class="ui-table">
<thead>
<tr><th>Customer</th><th>City</th><th>Last order</th></tr>
</thead>
<tbody>
<tr><td>Ayşe Yılmaz</td><td>Istanbul</td><td>Sep 12, 2026</td></tr>
<tr><td>Mehmet Kaya</td><td>Ankara</td><td>Sep 10, 2026</td></tr>
<tr><td>Zeynep Arslan</td><td>Izmir</td><td>Sep 8, 2026</td></tr>
</tbody>
</table>
</acun:table>
| Prop | Values |
|---|---|
ui-table | Class given to the table tag |
Numbers and alignment
Right-align number columns with text-right and write digits at equal width with tabular-nums so the digits line up. text-center can also be used for short codes and counts.
<acun:table>
<table class="ui-table">
<thead>
<tr><th>Product</th><th class="text-center">Code</th><th class="text-right">Sales</th><th class="text-right">Satisfaction</th></tr>
</thead>
<tbody>
<tr><td>Wireless headphones</td><td class="text-center">WH-01</td><td class="text-right tabular-nums">312</td><td class="text-right tabular-nums">91.4%</td></tr>
<tr><td>Mechanical keyboard</td><td class="text-center">MK-04</td><td class="text-right tabular-nums">148</td><td class="text-right tabular-nums">75.7%</td></tr>
<tr><td>USB-C charger</td><td class="text-center">UC-02</td><td class="text-right tabular-nums">96</td><td class="text-right tabular-nums">68.8%</td></tr>
</tbody>
</table>
</acun:table>
| Prop | Values |
|---|---|
text-right · text-center | Cell alignment |
tabular-nums | Equal-width digits |
Totals row
A row inside tfoot appears as a totals row, with bold text, a dark top border and a gray background.
<acun:table>
<table class="ui-table">
<thead>
<tr><th>Month</th><th class="text-right">Orders</th><th class="text-right">Returns</th></tr>
</thead>
<tbody>
<tr><td>September 2026</td><td class="text-right tabular-nums">1,248</td><td class="text-right tabular-nums">86</td></tr>
<tr><td>August 2026</td><td class="text-right tabular-nums">1,192</td><td class="text-right tabular-nums">104</td></tr>
</tbody>
<tfoot>
<tr><td>Total</td><td class="text-right tabular-nums">2,440</td><td class="text-right tabular-nums">190</td></tr>
</tfoot>
</table>
</acun:table>
| Prop | Values |
|---|---|
tfoot | Totals row style |
Sortable headers
acun:sortable-th is used instead of a plain th and, when clicked, calls the sortBy(field) method of the Livewire component (WithListing provides this method). sort-field and sort-direction take the current sort; the arrow of the matching column is highlighted and aria-sort is added. The header is a button that can also be used with the keyboard.
<acun:table>
<table class="ui-table">
<thead>
<tr>
<acun:sortable-th field="name" sort-field="sales" sort-direction="desc">Product</acun:sortable-th>
<acun:sortable-th field="sales" sort-field="sales" sort-direction="desc" class="text-right">Sales</acun:sortable-th>
</tr>
</thead>
<tbody>
<tr><td>Wireless headphones</td><td class="text-right tabular-nums">312</td></tr>
<tr><td>Mechanical keyboard</td><td class="text-right tabular-nums">148</td></tr>
</tbody>
</table>
</acun:table>
| Prop | Values |
|---|---|
field | Field name of this column |
sort-field | Current sort field ($sortField) |
sort-direction | asc | desc ($sortDirection) |
Status and actions
Show the status with acun:badge and the row actions with icon buttons on the right. Give icon buttons an aria-label; in cells with long text you can lift the single-line rule with whitespace-normal.
<acun:table>
<table class="ui-table">
<thead>
<tr><th>Product</th><th>Note</th><th>Status</th><th class="w-24"><span class="sr-only">Actions</span></th></tr>
</thead>
<tbody>
<tr>
<td class="font-medium text-gray-900 dark:text-zinc-100">Mechanical keyboard</td>
<td class="min-w-64 whitespace-normal">The supplier raises prices in November; the campaign price must stay valid until the end of October.</td>
<td><acun:badge variant="success">Active</acun:badge></td>
<td class="text-right">
<acun:button variant="ghost" size="icon" aria-label="Edit"><acun:icon name="pencil-square" /></acun:button>
<acun:button variant="ghost" size="icon" aria-label="Delete" class="text-red-600"><acun:icon name="trash" /></acun:button>
</td>
</tr>
</tbody>
</table>
</acun:table>
Empty table
When there are no records, keep the header row and put an acun:empty-state in a single cell; colspan must equal the number of columns.
<acun:table>
<table class="ui-table">
<thead>
<tr><th>Customer</th><th>City</th><th>Last order</th></tr>
</thead>
<tbody>
<tr>
<td colspan="3" class="whitespace-normal">
<acun:empty-state title="No records found" description="Try changing your search or filter criteria." class="border-0" />
</td>
</tr>
</tbody>
</table>
</acun:table>
Composable table
Instead of writing the table tag yourself, build the table from parts: acun:table.columns › acun:table.column, acun:table.rows › acun:table.row › acun:table.cell. When the content starts with a part, the component renders the <table class="ui-table"> tag itself. align (start · center · end) aligns the column and the cell.
<acun:table>
<acun:table.columns>
<acun:table.column>Project</acun:table.column>
<acun:table.column>Owner</acun:table.column>
<acun:table.column align="center">Status</acun:table.column>
<acun:table.column align="end">Tasks</acun:table.column>
<acun:table.column align="end">Progress</acun:table.column>
</acun:table.columns>
<acun:table.rows>
<acun:table.row>
<acun:table.cell class="font-medium text-gray-900 dark:text-zinc-100">Mobile app</acun:table.cell>
<acun:table.cell>Ahmet Yılmaz</acun:table.cell>
<acun:table.cell align="center"><acun:badge variant="info">In progress</acun:badge></acun:table.cell>
<acun:table.cell align="end" class="tabular-nums">42</acun:table.cell>
<acun:table.cell align="end" class="tabular-nums">64%</acun:table.cell>
</acun:table.row>
<acun:table.row>
<acun:table.cell class="font-medium text-gray-900 dark:text-zinc-100">Website</acun:table.cell>
<acun:table.cell>Elif Kaya</acun:table.cell>
<acun:table.cell align="center"><acun:badge variant="success">Completed</acun:badge></acun:table.cell>
<acun:table.cell align="end" class="tabular-nums">37</acun:table.cell>
<acun:table.cell align="end" class="tabular-nums">100%</acun:table.cell>
</acun:table.row>
<acun:table.row>
<acun:table.cell class="font-medium text-gray-900 dark:text-zinc-100">Checkout page</acun:table.cell>
<acun:table.cell>Murat Demir</acun:table.cell>
<acun:table.cell align="center"><acun:badge variant="warning">Delayed</acun:badge></acun:table.cell>
<acun:table.cell align="end" class="tabular-nums">51</acun:table.cell>
<acun:table.cell align="end" class="tabular-nums">38%</acun:table.cell>
</acun:table.row>
</acun:table.rows>
</acun:table>
Sorting in a composable table (Livewire)
A column with sortable and field calls your Livewire component's sortBy(field) method when clicked and announces the direction with aria-sort; give the sort state to acun:table once. The component must have $sortField, $sortDirection and sortBy() (WithListing provides them).
<acun:table :sort-field="$sortField" :sort-direction="$sortDirection">
<acun:table.columns>
<acun:table.column sortable field="name">Project</acun:table.column>
<acun:table.column sortable field="owner">Owner</acun:table.column>
<acun:table.column sortable field="tasks" align="end">Tasks</acun:table.column>
<acun:table.column align="end">Actions</acun:table.column>
</acun:table.columns>
<acun:table.rows>
@forelse ($projects as $project)
<acun:table.row wire:key="project-{{ $project->id }}">
<acun:table.cell class="font-medium text-gray-900 dark:text-zinc-100">{{ $project->name }}</acun:table.cell>
<acun:table.cell>{{ $project->owner }}</acun:table.cell>
<acun:table.cell align="end" class="tabular-nums">{{ $project->tasks }}</acun:table.cell>
<acun:table.cell align="end">
<acun:button size="icon" variant="soft" wire:click="edit({{ $project->id }})" aria-label="Edit" title="Edit">
<acun:icon name="pencil-square" size="4" />
</acun:button>
</acun:table.cell>
</acun:table.row>
@empty
<acun:table.row>
<acun:table.cell colspan="4" align="center" class="text-gray-500 dark:text-zinc-400">No projects match this filter.</acun:table.cell>
</acun:table.row>
@endforelse
</acun:table.rows>
</acun:table>
Props and slots
The values the component accepts.
| Prop | Default | Description |
|---|---|---|
acun:table | — | Attributes such as class are added to the scrollable container |
acun:table: sort-field · sort-direction | null | In composable usage, the shared sort state of the sortable columns |
table.column: align | start | start · center · end |
table.column: sortable · field | false · null | Sortable header; field is required, sortBy(field) is called on click |
table.cell: align | start | start · center · end |
ui-table (class) | — | On the table tag: header, cell, row hover and tfoot styles |
sortable-th: field | — | Required. sortBy(field) is called on click |
sortable-th: sort-field | — | Required. The current sort field |
sortable-th: sort-direction | — | Required. asc · desc |