| Invoice | Status | Method | Amount |
|---|---|---|---|
| INV001 | Paid | Credit Card | $250.00 |
| INV002 | Pending | PayPal | $150.00 |
| INV003 | Unpaid | Bank Transfer | $350.00 |
| INV004 | Paid | Credit Card | $450.00 |
| INV005 | Paid | PayPal | $550.00 |
| INV006 | Pending | Bank Transfer | $200.00 |
| INV007 | Unpaid | Credit Card | $300.00 |
| Total | $2,500.00 | ||
<script lang="ts">
import * as Table from "$lib/components/ui/table/index.js";
const invoices = [
{
invoice: "INV001",
paymentStatus: "Paid",
totalAmount: "$250.00",
paymentMethod: "Credit Card"
},
{
invoice: "INV002",
paymentStatus: "Pending",
totalAmount: "$150.00",
paymentMethod: "PayPal"
},
{
invoice: "INV003",
paymentStatus: "Unpaid",
totalAmount: "$350.00",
paymentMethod: "Bank Transfer"
},
{
invoice: "INV004",
paymentStatus: "Paid",
totalAmount: "$450.00",
paymentMethod: "Credit Card"
},
{
invoice: "INV005",
paymentStatus: "Paid",
totalAmount: "$550.00",
paymentMethod: "PayPal"
},
{
invoice: "INV006",
paymentStatus: "Pending",
totalAmount: "$200.00",
paymentMethod: "Bank Transfer"
},
{
invoice: "INV007",
paymentStatus: "Unpaid",
totalAmount: "$300.00",
paymentMethod: "Credit Card"
}
];
</script>
<Table.Root>
<Table.Caption>A list of your recent invoices.</Table.Caption>
<Table.Header>
<Table.Row>
<Table.Head class="w-[100px]">Invoice</Table.Head>
<Table.Head>Status</Table.Head>
<Table.Head>Method</Table.Head>
<Table.Head class="text-end">Amount</Table.Head>
</Table.Row>
</Table.Header>
<Table.Body>
{#each invoices as invoice (invoice)}
<Table.Row>
<Table.Cell class="font-medium">{invoice.invoice}</Table.Cell>
<Table.Cell>{invoice.paymentStatus}</Table.Cell>
<Table.Cell>{invoice.paymentMethod}</Table.Cell>
<Table.Cell class="text-end">{invoice.totalAmount}</Table.Cell>
</Table.Row>
{/each}
</Table.Body>
<Table.Footer>
<Table.Row>
<Table.Cell colspan={3}>Total</Table.Cell>
<Table.Cell class="text-end">$2,500.00</Table.Cell>
</Table.Row>
</Table.Footer>
</Table.Root> Installation
pnpm dlx shadcn-svelte@latest add table Copy and paste the following code into your project.
import Root from './table.svelte';
import Body from './table-body.svelte';
import Caption from './table-caption.svelte';
import Cell from './table-cell.svelte';
import Footer from './table-footer.svelte';
import Head from './table-head.svelte';
import Header from './table-header.svelte';
import Row from './table-row.svelte';
export {
Root,
Body,
Caption,
Cell,
Footer,
Head,
Header,
Row,
//
Root as Table,
Body as TableBody,
Caption as TableCaption,
Cell as TableCell,
Footer as TableFooter,
Head as TableHead,
Header as TableHeader,
Row as TableRow
};
<script lang="ts">
import { cn, type WithElementRef } from '$UTILS$.js';
import type { HTMLAttributes } from 'svelte/elements';
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLTableSectionElement>> = $props();
</script>
<tbody
bind:this={ref}
data-slot="table-body"
class={cn('[&_tr:last-child]:border-b-0', className)}
{...restProps}
>
{@render children?.()}
</tbody>
<script lang="ts">
import { cn, type WithElementRef } from '$UTILS$.js';
import type { HTMLAttributes } from 'svelte/elements';
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLElement>> = $props();
</script>
<caption
bind:this={ref}
data-slot="table-caption"
class={cn('mt-4 font-mono text-xs tracking-[0.14em] text-zinc-500 uppercase', className)}
{...restProps}
>
{@render children?.()}
</caption>
<script lang="ts">
import { cn, type WithElementRef } from '$UTILS$.js';
import type { HTMLTdAttributes } from 'svelte/elements';
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLTdAttributes> = $props();
</script>
<td
bind:this={ref}
data-slot="table-cell"
class={cn(
'border-r border-zinc-900 px-3 py-2.5 align-middle whitespace-nowrap text-zinc-300 last:border-r-0 [&:has([role=checkbox])]:pr-0',
className
)}
{...restProps}
>
{@render children?.()}
</td>
<script lang="ts">
import { cn, type WithElementRef } from '$UTILS$.js';
import type { HTMLAttributes } from 'svelte/elements';
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLTableSectionElement>> = $props();
</script>
<tfoot
bind:this={ref}
data-slot="table-footer"
class={cn(
'border-t border-zinc-800 bg-zinc-950 font-medium text-zinc-100 [&>tr]:last:border-b-0',
className
)}
{...restProps}
>
{@render children?.()}
</tfoot>
<script lang="ts">
import { cn, type WithElementRef } from '$UTILS$.js';
import type { HTMLThAttributes } from 'svelte/elements';
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLThAttributes> = $props();
</script>
<th
bind:this={ref}
data-slot="table-head"
class={cn(
'h-10 border-r border-zinc-900 px-3 text-left align-middle font-mono text-xs font-semibold tracking-[0.14em] whitespace-nowrap text-zinc-500 uppercase last:border-r-0 [&:has([role=checkbox])]:pr-0',
className
)}
{...restProps}
>
{@render children?.()}
</th>
<script lang="ts">
import { cn, type WithElementRef } from '$UTILS$.js';
import type { HTMLAttributes } from 'svelte/elements';
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLTableSectionElement>> = $props();
</script>
<thead
bind:this={ref}
data-slot="table-header"
class={cn('bg-zinc-950/80 [&_tr]:border-b [&_tr]:border-zinc-800', className)}
{...restProps}
>
{@render children?.()}
</thead>
<script lang="ts">
import { cn, type WithElementRef } from '$UTILS$.js';
import type { HTMLAttributes } from 'svelte/elements';
let {
ref = $bindable(null),
class: className,
children,
...restProps
}: WithElementRef<HTMLAttributes<HTMLTableRowElement>> = $props();
</script>
<tr
bind:this={ref}
data-slot="table-row"
class={cn(
'border-b border-zinc-900 transition-colors hover:bg-zinc-950 data-[state=selected]:bg-[#b9d765]/20',
className
)}
{...restProps}
>
{@render children?.()}
</tr>
<script lang="ts">
import type { HTMLTableAttributes } from 'svelte/elements';
import { cn, type WithElementRef } from '$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 border border-zinc-800 bg-background"
>
<table
bind:this={ref}
data-slot="table"
class={cn('w-full caption-bottom border-collapse text-sm text-zinc-300', className)}
{...restProps}
>
{@render children?.()}
</table>
</div>
Usage
<script lang="ts">
import * as Table from '$lib/components/ui/table/index.js';
</script> <Table.Root>
<Table.Caption>A list of your recent invoices.</Table.Caption>
<Table.Header>
<Table.Row>
<Table.Head class="w-[100px]">Invoice</Table.Head>
<Table.Head>Status</Table.Head>
<Table.Head>Method</Table.Head>
<Table.Head class="text-end">Amount</Table.Head>
</Table.Row>
</Table.Header>
<Table.Body>
<Table.Row>
<Table.Cell class="font-medium">INV001</Table.Cell>
<Table.Cell>Paid</Table.Cell>
<Table.Cell>Credit Card</Table.Cell>
<Table.Cell class="text-end">$250.00</Table.Cell>
</Table.Row>
</Table.Body>
</Table.Root> Data Table
You can use the <Table /> component to build more complex data tables. Combine it with @tanstack/table to create tables with sorting, filtering and pagination.
See the Data Table documentation for more information.