Table
Semantic <table> primitive with styled head, body, row, cell, and caption slots. No motion beyond a quick row-hover color transition — plain tabular data, rendered well.
Usage
| Invoice | Status | Method | Amount |
|---|---|---|---|
| INV-001 | Paid | Credit Card | $250.00 |
| INV-002 | Pending | PayPal | $150.00 |
| INV-003 | Overdue | Bank Transfer | $350.00 |
| INV-004 | Paid | Credit Card | $450.00 |
| INV-005 | Paid | Apple Pay | $120.00 |
table.svelte
<script lang="ts">
import type { HTMLTableAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils.js';
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLTableAttributes> = $props();
</script>
<div data-slot="table-container" class="relative w-full overflow-x-auto">
<table
bind:this={ref}
data-slot="table"
class={cn('w-full caption-bottom text-sm', className)}
{...restProps}
>
{@render children?.()}
</table>
</div>
With footer
| Invoice | Status | Amount |
|---|---|---|
| INV-001 | Paid | $250.00 |
| INV-002 | Pending | $150.00 |
| INV-003 | Overdue | $350.00 |
| Total | $750.00 | |
table.svelte
<script lang="ts">
import type { HTMLTableAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils.js';
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLTableAttributes> = $props();
</script>
<div data-slot="table-container" class="relative w-full overflow-x-auto">
<table
bind:this={ref}
data-slot="table"
class={cn('w-full caption-bottom text-sm', className)}
{...restProps}
>
{@render children?.()}
</table>
</div>
Zebra
Add even:bg-muted/30 on the row to alternate background tone
— useful for dense lists where row separation is the primary affordance.
| Invoice | Status | Method | Amount |
|---|---|---|---|
| INV-001 | Paid | Credit Card | $250.00 |
| INV-002 | Pending | PayPal | $150.00 |
| INV-003 | Overdue | Bank Transfer | $350.00 |
| INV-004 | Paid | Credit Card | $450.00 |
| INV-005 | Paid | Apple Pay | $120.00 |
table-zebra.svelte
<script lang="ts">
import type { HTMLTableAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils.js';
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLTableAttributes> = $props();
</script>
<div data-slot="table-container" class="relative w-full overflow-x-auto">
<table
bind:this={ref}
data-slot="table"
class={cn('w-full caption-bottom text-sm', className)}
{...restProps}
>
{@render children?.()}
</table>
</div>
Sticky header
Constrain the wrapper height and set sticky top-0 bg-background on the header — keeps the column labels visible when the body scrolls.
| Invoice | Status | Method | Amount |
|---|---|---|---|
| INV-001 | Paid | Credit Card | $250.00 |
| INV-002 | Pending | PayPal | $150.00 |
| INV-003 | Overdue | Bank Transfer | $350.00 |
| INV-004 | Paid | Credit Card | $450.00 |
| INV-005 | Paid | Apple Pay | $120.00 |
| INV-001 | Paid | Credit Card | $250.00 |
| INV-002 | Pending | PayPal | $150.00 |
| INV-003 | Overdue | Bank Transfer | $350.00 |
| INV-004 | Paid | Credit Card | $450.00 |
| INV-005 | Paid | Apple Pay | $120.00 |
| INV-001 | Paid | Credit Card | $250.00 |
| INV-002 | Pending | PayPal | $150.00 |
| INV-003 | Overdue | Bank Transfer | $350.00 |
| INV-004 | Paid | Credit Card | $450.00 |
| INV-005 | Paid | Apple Pay | $120.00 |
table-sticky.svelte
<script lang="ts">
import type { HTMLTableAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$lib/utils.js';
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLTableAttributes> = $props();
</script>
<div data-slot="table-container" class="relative w-full overflow-x-auto">
<table
bind:this={ref}
data-slot="table"
class={cn('w-full caption-bottom text-sm', className)}
{...restProps}
>
{@render children?.()}
</table>
</div>
Table.* props
Every subcomponent forwards its native HTML attributes. The surface styling lives in tailwind classes; override per slot by merging via class.
| Prop | Type | Default | Description |
|---|---|---|---|
HTMLTableAttributes | — | The <table> element. Wrapped in a scroll-x container. | |
HTMLAttributes<HTMLElement> | — | The <caption> element. Rendered below the table by default. | |
HTMLAttributes<HTMLTableSectionElement> | — | <thead>. Adds a bottom border to the final row inside. | |
HTMLAttributes<HTMLTableSectionElement> | — | <tbody>. Omits the bottom border on the last row. | |
HTMLAttributes<HTMLTableSectionElement> | — | <tfoot>. Muted background + top border; intended for totals. | |
HTMLAttributes<HTMLTableRowElement> | — | <tr>. Hover state paints a subtle muted background; data-state="selected" applies the selected tone. | |
HTMLThAttributes | — | <th>. Left-aligned, medium-weight, whitespace-nowrap. | |
HTMLTdAttributes | — | <td>. Middle-aligned, whitespace-nowrap. |