Skip to content
tcpsystemsui

Theme

Colour scheme
Accent
Density
Radius
Esc

Table

Native table in a named, focusable scroll region.

beta

Try it

Svelte
<Table label="Data table" height="bounded" />

Examples

Deployments

EnvironmentBuildStatusStarted
production#1247deployed2026-11-06 14:22
staging#1246building2026-11-06 14:18
preview#1245pending approval2026-11-06 13:45
development#1244failed2026-11-06 12:30
Deployments.svelte
<script lang="ts">
	import Table from '@tcpsystems/ui/foundation/Table';
	import Stack from '@tcpsystems/ui/foundation/Stack';
	import Cluster from '@tcpsystems/ui/foundation/Cluster';
	import Badge from '@tcpsystems/ui/foundation/Badge';
	import Status from '@tcpsystems/ui/foundation/Status';
	import Button from '@tcpsystems/ui/foundation/Button';
	import Icon from '@tcpsystems/ui/foundation/Icon';
</script>

<Stack data-gap="lg">
	<Table label="Recent deployments">
		<thead>
			<tr>
				<Table mode="sort-header" href="#" sort="descending">Environment</Table>
				<Table mode="sort-header" href="#" kind="num">Build</Table>
				<Table mode="sort-header" href="#">Status</Table>
				<Table mode="sort-header" href="#" sort="ascending">Started</Table>
				<th scope="col"></th>
			</tr>
		</thead>
		<tbody>
			<tr>
				<td>production</td>
				<td>#1247</td>
				<td><Status tone="ok">deployed</Status></td>
				<td>2026-11-06 14:22</td>
				<td><Button variant="ghost" icon="eye" aria-label="View deployment" /></td>
			</tr>
			<tr>
				<td>staging</td>
				<td>#1246</td>
				<td><Status tone="progress">building</Status></td>
				<td>2026-11-06 14:18</td>
				<td><Button variant="ghost" icon="eye" aria-label="View deployment" /></td>
			</tr>
			<tr>
				<td>preview</td>
				<td>#1245</td>
				<td><Status tone="warn">pending approval</Status></td>
				<td>2026-11-06 13:45</td>
				<td><Button variant="ghost" icon="eye" aria-label="View deployment" /></td>
			</tr>
			<tr>
				<td>development</td>
				<td>#1244</td>
				<td><Status tone="danger">failed</Status></td>
				<td>2026-11-06 12:30</td>
				<td><Button variant="ghost" icon="eye" aria-label="View deployment" /></td>
			</tr>
		</tbody>
	</Table>
	<Cluster justify="end">
		<Button variant="ghost">View all deployments</Button>
	</Cluster>
</Stack>

Empty and bounded

IncidentSeverityServiceSince

No active incidents

Empty and bounded.svelte
<script lang="ts">
	import Table from '@tcpsystems/ui/foundation/Table';
	import Stack from '@tcpsystems/ui/foundation/Stack';
	import Cluster from '@tcpsystems/ui/foundation/Cluster';
	import EmptyState from '@tcpsystems/ui/foundation/EmptyState';
	import Button from '@tcpsystems/ui/foundation/Button';
	const uid = $props.id();
	let busy = $state(false);
</script>

<Stack data-gap="lg">
	<Table label="Incidents" height="bounded" {busy}>
		<thead>
			<tr>
				<Table mode="sort-header" href="#" sort="descending">Incident</Table>
				<Table mode="sort-header" href="#" kind="num">Severity</Table>
				<Table mode="sort-header" href="#">Service</Table>
				<Table mode="sort-header" href="#">Since</Table>
				<th scope="col"></th>
			</tr>
		</thead>
		<tbody>
			{#if busy}
				<tr><td colspan="5"><EmptyState title="Loading incidents…" /></td></tr>
			{:else}
				<tr>
					<td colspan="5">
						<EmptyState title="No active incidents">
							{#snippet actions()}
								<Button variant="primary" icon="plus">Create incident</Button>
							{/snippet}
						</EmptyState>
					</td>
				</tr>
			{/if}
		</tbody>
	</Table>
	<Cluster>
		<Button variant="ghost" onclick={() => busy = !busy}>{busy ? 'Done loading' : 'Simulate loading'}</Button>
	</Cluster>
</Stack>

API

Import
import Table from '@tcpsystems/ui/foundation/Table';
PropTypeDefault
mode?'table' | 'sort-header''table'
label?stringnone
height?'bounded'none
busy?booleanfalse
href?stringnone
sort?'none' | 'ascending' | 'descending''none'
kind?'num'none
priority?'medium' | 'low'none
Snippet
children
HookKind
.tcp-table-frameRoot class
data-heightData attribute
data-kindData attribute
data-priorityData attribute