<SYSTEM>This is the llms.txt documentation for the "tables" directory of the Origin UI - Svelte project.</SYSTEM>

# "tables" directory

> A collection of production-ready, accessible UI components built with Svelte 5 and Tailwind CSS. These components are designed to be drop-in solutions for rapidly building modern web applications.

This documentation covers 20 components, each following best practices for accessibility, performance, and type safety.

## Components


## table-01

> A type-safe, accessible table-01 component for building modern UIs. This component is part of the tables collection.

### Core Information

- **Component ID**: `table-01`
- **Location**: `/src/lib/components/tables/table-01.svelte`
- **Type**: UI Component

### Usage

```svelte
Full component implementation:

```svelte
<script lang="ts">
	import {
		Table,
		TableBody,
		TableCell,
		TableFooter,
		TableHead,
		TableHeader,
		TableRow
	} from '$lib/components/ui/table';

	const items = [
		{
			balance: '$1,250.00',
			email: 'alex.t@company.com',
			id: '1',
			location: 'San Francisco, US',
			name: 'Alex Thompson',
			status: 'Active'
		},
		{
			balance: '$600.00',
			email: 'sarah.c@company.com',
			id: '2',
			location: 'Singapore',
			name: 'Sarah Chen',
			status: 'Active'
		},
		{
			balance: '$650.00',
			email: 'j.wilson@company.com',
			id: '3',
			location: 'London, UK',
			name: 'James Wilson',
			status: 'Inactive'
		},
		{
			balance: '$0.00',
			email: 'm.garcia@company.com',
			id: '4',
			location: 'Madrid, Spain',
			name: 'Maria Garcia',
			status: 'Active'
		},
		{
			balance: '-$1,000.00',
			email: 'd.kim@company.com',
			id: '5',
			location: 'Seoul, KR',
			name: 'David Kim',
			status: 'Active'
		}
	];
</script>

<div>
	<Table>
		<TableHeader>
			<TableRow class="hover:bg-transparent">
				<TableHead>Name</TableHead>
				<TableHead>Email</TableHead>
				<TableHead>Location</TableHead>
				<TableHead>Status</TableHead>
				<TableHead class="text-right">Balance</TableHead>
			</TableRow>
		</TableHeader>
		<TableBody>
			{#each items as item (item.id)}
				<TableRow>
					<TableCell class="font-medium">{item.name}</TableCell>
					<TableCell>{item.email}</TableCell>
					<TableCell>{item.location}</TableCell>
					<TableCell>{item.status}</TableCell>
					<TableCell class="text-right">{item.balance}</TableCell>
				</TableRow>
			{/each}
		</TableBody>
		<TableFooter class="bg-transparent">
			<TableRow class="hover:bg-transparent">
				<TableCell colspan={4}>Total</TableCell>
				<TableCell class="text-right">$2,500.00</TableCell>
			</TableRow>
		</TableFooter>
	</Table>
	<p class="mt-4 text-center text-sm text-muted-foreground">Basic table</p>
</div>

```

### Links

- [View Source](https://github.com/max-got/originui-svelte/tree/main/src/lib/components/tables/table-01.svelte)


## table-02

> A type-safe, accessible table-02 component for building modern UIs. This component is part of the tables collection.

### Core Information

- **Component ID**: `table-02`
- **Location**: `/src/lib/components/tables/table-02.svelte`
- **Type**: UI Component

### Usage

```svelte
Full component implementation:

```svelte
<script lang="ts">
	import {
		Table,
		TableBody,
		TableCell,
		TableHead,
		TableHeader,
		TableRow
	} from '$lib/components/ui/table';

	const items = [
		{
			balance: '$1,250.00',
			email: 'alex.t@company.com',
			id: '1',
			image:
				'https://res.cloudinary.com/dlzlfasou/image/upload/v1736358071/avatar-40-02_upqrxi.jpg',
			location: 'San Francisco, US',
			name: 'Alex Thompson',
			status: 'Active',
			username: '@alexthompson'
		},
		{
			balance: '$600.00',
			email: 'sarah.c@company.com',
			id: '2',
			image:
				'https://res.cloudinary.com/dlzlfasou/image/upload/v1736358073/avatar-40-01_ij9v7j.jpg',
			location: 'Singapore',
			name: 'Sarah Chen',
			status: 'Active',
			username: '@sarahchen'
		},
		{
			balance: '$0.00',
			email: 'm.garcia@company.com',
			id: '4',
			image:
				'https://res.cloudinary.com/dlzlfasou/image/upload/v1736358072/avatar-40-03_dkeufx.jpg',
			location: 'Madrid, Spain',
			name: 'Maria Garcia',
			status: 'Active',
			username: '@mariagarcia'
		},
		{
			balance: '-$1,000.00',
			email: 'd.kim@company.com',
			id: '5',
			image:
				'https://res.cloudinary.com/dlzlfasou/image/upload/v1736358070/avatar-40-05_cmz0mg.jpg',
			location: 'Seoul, KR',
			name: 'David Kim',
			status: 'Active',
			username: '@davidkim'
		}
	];
</script>

<div>
	<Table>
		<TableHeader>
			<TableRow class="hover:bg-transparent">
				<TableHead>Name</TableHead>
				<TableHead>Email</TableHead>
				<TableHead>Location</TableHead>
				<TableHead>Status</TableHead>
				<TableHead class="text-right">Balance</TableHead>
			</TableRow>
		</TableHeader>
		<TableBody>
			{#each items as item (item.id)}
				<TableRow>
					<TableCell>
						<div class="flex items-center gap-3">
							<img class="rounded-full" src={item.image} width={40} height={40} alt={item.name} />
							<div>
								<div class="font-medium">{item.name}</div>
								<span class="mt-0.5 text-xs text-muted-foreground">
									{item.username}
								</span>
							</div>
						</div>
					</TableCell>
					<TableCell>{item.email}</TableCell>
					<TableCell>{item.location}</TableCell>
					<TableCell>{item.status}</TableCell>
					<TableCell class="text-right">{item.balance}</TableCell>
				</TableRow>
			{/each}
		</TableBody>
	</Table>
	<p class="mt-4 text-center text-sm text-muted-foreground">Table with images</p>
</div>

```

### Links

- [View Source](https://github.com/max-got/originui-svelte/tree/main/src/lib/components/tables/table-02.svelte)


## table-03

> A type-safe, accessible table-03 component for building modern UIs. This component is part of the tables collection.

### Core Information

- **Component ID**: `table-03`
- **Location**: `/src/lib/components/tables/table-03.svelte`
- **Type**: UI Component

### Usage

```svelte
Full component implementation:

```svelte
<script lang="ts">
	import {
		Table,
		TableBody,
		TableCell,
		TableFooter,
		TableHead,
		TableHeader,
		TableRow
	} from '$lib/components/ui/table';

	const items = [
		{
			balance: '$1,250.00',
			email: 'alex.t@company.com',
			id: '1',
			location: 'San Francisco, US',
			name: 'Alex Thompson',
			status: 'Active'
		},
		{
			balance: '$600.00',
			email: 'sarah.c@company.com',
			id: '2',
			location: 'Singapore',
			name: 'Sarah Chen',
			status: 'Active'
		},
		{
			balance: '$650.00',
			email: 'j.wilson@company.com',
			id: '3',
			location: 'London, UK',
			name: 'James Wilson',
			status: 'Inactive'
		},
		{
			balance: '$0.00',
			email: 'm.garcia@company.com',
			id: '4',
			location: 'Madrid, Spain',
			name: 'Maria Garcia',
			status: 'Active'
		},
		{
			balance: '-$1,000.00',
			email: 'd.kim@company.com',
			id: '5',
			location: 'Seoul, KR',
			name: 'David Kim',
			status: 'Active'
		}
	];
</script>

<div>
	<Table>
		<TableHeader>
			<TableRow class="hover:bg-transparent">
				<TableHead>Name</TableHead>
				<TableHead>Email</TableHead>
				<TableHead>Location</TableHead>
				<TableHead>Status</TableHead>
				<TableHead class="text-right">Balance</TableHead>
			</TableRow>
		</TableHeader>
		<tbody aria-hidden="true" class="table-row h-2"></tbody>
		<TableBody class="[&_td:first-child]:rounded-l-lg [&_td:last-child]:rounded-r-lg">
			{#each items as item (item.id)}
				<TableRow class="border-none">
					<TableCell class="py-2.5 font-medium">{item.name}</TableCell>
					<TableCell class="py-2.5">{item.email}</TableCell>
					<TableCell class="py-2.5">{item.location}</TableCell>
					<TableCell class="py-2.5">{item.status}</TableCell>
					<TableCell class="py-2.5 text-right">
						{item.balance}
					</TableCell>
				</TableRow>
			{/each}
		</TableBody>
		<tbody aria-hidden="true" class="table-row h-2"></tbody>
		<TableFooter class="bg-transparent">
			<TableRow class="hover:bg-transparent">
				<TableCell colspan={4}>Total</TableCell>
				<TableCell class="text-right">$2,500.00</TableCell>
			</TableRow>
		</TableFooter>
	</Table>
	<p class="mt-4 text-center text-sm text-muted-foreground">Table without horizontal dividers</p>
</div>

```

### Links

- [View Source](https://github.com/max-got/originui-svelte/tree/main/src/lib/components/tables/table-03.svelte)


## table-04

> A type-safe, accessible table-04 component for building modern UIs. This component is part of the tables collection.

### Core Information

- **Component ID**: `table-04`
- **Location**: `/src/lib/components/tables/table-04.svelte`
- **Type**: UI Component

### Usage

```svelte
Full component implementation:

```svelte
<script lang="ts">
	import {
		Table,
		TableBody,
		TableCell,
		TableFooter,
		TableHead,
		TableHeader,
		TableRow
	} from '$lib/components/ui/table';

	const items = [
		{
			balance: '$1,250.00',
			email: 'alex.t@company.com',
			id: '1',
			location: 'San Francisco, US',
			name: 'Alex Thompson',
			status: 'Active'
		},
		{
			balance: '$600.00',
			email: 'sarah.c@company.com',
			id: '2',
			location: 'Singapore',
			name: 'Sarah Chen',
			status: 'Active'
		},
		{
			balance: '$650.00',
			email: 'j.wilson@company.com',
			id: '3',
			location: 'London, UK',
			name: 'James Wilson',
			status: 'Inactive'
		},
		{
			balance: '$0.00',
			email: 'm.garcia@company.com',
			id: '4',
			location: 'Madrid, Spain',
			name: 'Maria Garcia',
			status: 'Active'
		},
		{
			balance: '-$1,000.00',
			email: 'd.kim@company.com',
			id: '5',
			location: 'Seoul, KR',
			name: 'David Kim',
			status: 'Active'
		}
	];
</script>

<div>
	<Table>
		<TableHeader class="bg-transparent">
			<TableRow class="hover:bg-transparent">
				<TableHead>Name</TableHead>
				<TableHead>Email</TableHead>
				<TableHead>Location</TableHead>
				<TableHead>Status</TableHead>
				<TableHead class="text-right">Balance</TableHead>
			</TableRow>
		</TableHeader>
		<tbody aria-hidden="true" class="table-row h-2"></tbody>
		<TableBody class="[&_td:first-child]:rounded-l-lg [&_td:last-child]:rounded-r-lg">
			{#each items as item (item.id)}
				<TableRow class="border-none odd:bg-muted/50 hover:bg-transparent odd:hover:bg-muted/50">
					<TableCell class="py-2.5 font-medium">{item.name}</TableCell>
					<TableCell class="py-2.5">{item.email}</TableCell>
					<TableCell class="py-2.5">{item.location}</TableCell>
					<TableCell class="py-2.5">{item.status}</TableCell>
					<TableCell class="py-2.5 text-right">
						{item.balance}
					</TableCell>
				</TableRow>
			{/each}
		</TableBody>
		<tbody aria-hidden="true" class="table-row h-2"></tbody>
		<TableFooter class="bg-transparent">
			<TableRow class="hover:bg-transparent">
				<TableCell colspan={4}>Total</TableCell>
				<TableCell class="text-right">$2,500.00</TableCell>
			</TableRow>
		</TableFooter>
	</Table>
	<p class="mt-4 text-center text-sm text-muted-foreground">Striped table</p>
</div>

```

### Links

- [View Source](https://github.com/max-got/originui-svelte/tree/main/src/lib/components/tables/table-04.svelte)


## table-05

> A type-safe, accessible table-05 component for building modern UIs. This component is part of the tables collection.

### Core Information

- **Component ID**: `table-05`
- **Location**: `/src/lib/components/tables/table-05.svelte`
- **Type**: UI Component

### Usage

```svelte
Full component implementation:

```svelte
<script lang="ts">
	import {
		Table,
		TableBody,
		TableCell,
		TableHead,
		TableHeader,
		TableRow
	} from '$lib/components/ui/table';

	const items = [
		{
			balance: '$1,250.00',
			email: 'alex.t@company.com',
			id: '1',
			location: 'San Francisco, US',
			name: 'Alex Thompson',
			status: 'Active'
		},
		{
			balance: '$600.00',
			email: 'sarah.c@company.com',
			id: '2',
			location: 'Singapore',
			name: 'Sarah Chen',
			status: 'Active'
		},
		{
			balance: '$650.00',
			email: 'j.wilson@company.com',
			id: '3',
			location: 'London, UK',
			name: 'James Wilson',
			status: 'Inactive'
		},
		{
			balance: '$0.00',
			email: 'm.garcia@company.com',
			id: '4',
			location: 'Madrid, Spain',
			name: 'Maria Garcia',
			status: 'Active'
		},
		{
			balance: '-$1,000.00',
			email: 'd.kim@company.com',
			id: '5',
			location: 'Seoul, KR',
			name: 'David Kim',
			status: 'Active'
		}
	];
</script>

<div>
	<Table>
		<TableHeader class="bg-transparent">
			<TableRow class="*:border-border hover:bg-transparent [&>:not(:last-child)]:border-r">
				<TableHead>Name</TableHead>
				<TableHead>Email</TableHead>
				<TableHead>Location</TableHead>
				<TableHead>Status</TableHead>
				<TableHead class="text-right">Balance</TableHead>
			</TableRow>
		</TableHeader>
		<TableBody class="[&_td:first-child]:rounded-l-lg [&_td:last-child]:rounded-r-lg">
			{#each items as item (item.id)}
				<TableRow class="*:border-border hover:bg-transparent [&>:not(:last-child)]:border-r">
					<TableCell class="font-medium">{item.name}</TableCell>
					<TableCell>{item.email}</TableCell>
					<TableCell>{item.location}</TableCell>
					<TableCell>{item.status}</TableCell>
					<TableCell class="text-right">{item.balance}</TableCell>
				</TableRow>
			{/each}
		</TableBody>
	</Table>
	<p class="mt-4 text-center text-sm text-muted-foreground">Table with vertical lines</p>
</div>

```

### Links

- [View Source](https://github.com/max-got/originui-svelte/tree/main/src/lib/components/tables/table-05.svelte)


## table-06

> A type-safe, accessible table-06 component for building modern UIs. This component is part of the tables collection.

### Core Information

- **Component ID**: `table-06`
- **Location**: `/src/lib/components/tables/table-06.svelte`
- **Type**: UI Component

### Usage

```svelte
Full component implementation:

```svelte
<script lang="ts">
	import {
		Table,
		TableBody,
		TableCell,
		TableHead,
		TableHeader,
		TableRow
	} from '$lib/components/ui/table';

	const programmingLanguages = [
		{
			developer: 'Brendan Eich',
			extension: '.js',
			id: '1',
			latestVersion: 'ES2021',
			name: 'JavaScript',
			paradigm: 'Multi-paradigm',
			popularity: 'High',
			releaseYear: '1995',
			typing: 'Dynamic'
		},
		{
			developer: 'Guido van Rossum',
			extension: '.py',
			id: '2',
			latestVersion: '3.10',
			name: 'Python',
			paradigm: 'Multi-paradigm',
			popularity: 'High',
			releaseYear: '1991',
			typing: 'Dynamic'
		},
		{
			developer: 'James Gosling',
			extension: '.java',
			id: '3',
			latestVersion: '17',
			name: 'Java',
			paradigm: 'Object-oriented',
			popularity: 'High',
			releaseYear: '1995',
			typing: 'Static'
		},
		{
			developer: 'Bjarne Stroustrup',
			extension: '.cpp',
			id: '4',
			latestVersion: 'C++20',
			name: 'C++',
			paradigm: 'Multi-paradigm',
			popularity: 'High',
			releaseYear: '1985',
			typing: 'Static'
		},
		{
			developer: 'Yukihiro Matsumoto',
			extension: '.rb',
			id: '5',
			latestVersion: '3.0',
			name: 'Ruby',
			paradigm: 'Multi-paradigm',
			popularity: 'Low',
			releaseYear: '1995',
			typing: 'Dynamic'
		}
	];
</script>

<div>
	<div class="overflow-hidden rounded-md border bg-background">
		<Table>
			<TableHeader>
				<TableRow class="bg-muted/50">
					<TableHead class="h-9 py-2">Name</TableHead>
					<TableHead class="h-9 py-2">Release Year</TableHead>
					<TableHead class="h-9 py-2">Developer</TableHead>
					<TableHead class="h-9 py-2">Typing</TableHead>
					<TableHead class="h-9 py-2">Paradigm</TableHead>
					<TableHead class="h-9 py-2">Extension</TableHead>
					<TableHead class="h-9 py-2">Latest Version</TableHead>
					<TableHead class="h-9 py-2">Popularity</TableHead>
				</TableRow>
			</TableHeader>
			<TableBody>
				{#each programmingLanguages as language (language.id)}
					<TableRow>
						<TableCell class="py-2 font-medium">
							{language.name}
						</TableCell>
						<TableCell class="py-2">{language.releaseYear}</TableCell>
						<TableCell class="py-2">{language.developer}</TableCell>
						<TableCell class="py-2">{language.typing}</TableCell>
						<TableCell class="py-2">{language.paradigm}</TableCell>
						<TableCell class="py-2">{language.extension}</TableCell>
						<TableCell class="py-2">{language.latestVersion}</TableCell>
						<TableCell class="py-2">{language.popularity}</TableCell>
					</TableRow>
				{/each}
			</TableBody>
		</Table>
	</div>
	<p class="mt-4 text-center text-sm text-muted-foreground">Dense table</p>
</div>

```

### Links

- [View Source](https://github.com/max-got/originui-svelte/tree/main/src/lib/components/tables/table-06.svelte)


## table-07

> A type-safe, accessible table-07 component for building modern UIs. This component is part of the tables collection.

### Core Information

- **Component ID**: `table-07`
- **Location**: `/src/lib/components/tables/table-07.svelte`
- **Type**: UI Component

### Usage

```svelte
Full component implementation:

```svelte
<script lang="ts">
	import Checkbox from '$lib/components/ui/checkbox.svelte';

	import {
		Table,
		TableBody,
		TableCell,
		TableFooter,
		TableHead,
		TableHeader,
		TableRow
	} from '$lib/components/ui/table';

	const items = [
		{
			balance: '$1,250.00',
			email: 'alex.t@company.com',
			id: '1',
			location: 'San Francisco, US',
			name: 'Alex Thompson',
			status: 'Active'
		},
		{
			balance: '$600.00',
			email: 'sarah.c@company.com',
			id: '2',
			location: 'Singapore',
			name: 'Sarah Chen',
			status: 'Active'
		},
		{
			balance: '$650.00',
			email: 'j.wilson@company.com',
			id: '3',
			location: 'London, UK',
			name: 'James Wilson',
			status: 'Inactive'
		},
		{
			balance: '$0.00',
			email: 'm.garcia@company.com',
			id: '4',
			location: 'Madrid, Spain',
			name: 'Maria Garcia',
			status: 'Active'
		},
		{
			balance: '-$1,000.00',
			email: 'd.kim@company.com',
			id: '5',
			location: 'Seoul, KR',
			name: 'David Kim',
			status: 'Active'
		}
	];

	const id = $props.id();
</script>

<div>
	<Table>
		<TableHeader>
			<TableRow class="hover:bg-transparent">
				<TableHead>
					<Checkbox {id} />
				</TableHead>
				<TableHead>Name</TableHead>
				<TableHead>Email</TableHead>
				<TableHead>Location</TableHead>
				<TableHead>Status</TableHead>
				<TableHead class="text-right">Balance</TableHead>
			</TableRow>
		</TableHeader>
		<TableBody>
			{#each items as item (item.id)}
				<TableRow class="has-data-[state=checked]:bg-muted/50">
					<TableCell>
						<Checkbox id="table-checkbox-{item.id}" />
					</TableCell>
					<TableCell class="font-medium">{item.name}</TableCell>
					<TableCell>{item.email}</TableCell>
					<TableCell>{item.location}</TableCell>
					<TableCell>{item.status}</TableCell>
					<TableCell class="text-right">{item.balance}</TableCell>
				</TableRow>
			{/each}
		</TableBody>
		<TableFooter class="bg-transparent">
			<TableRow class="hover:bg-transparent">
				<TableCell colspan={5}>Total</TableCell>
				<TableCell class="text-right">$2,500.00</TableCell>
			</TableRow>
		</TableFooter>
	</Table>
	<p class="mt-4 text-center text-sm text-muted-foreground">Table with row selection</p>
</div>

```

### Links

- [View Source](https://github.com/max-got/originui-svelte/tree/main/src/lib/components/tables/table-07.svelte)


## table-08

> A type-safe, accessible table-08 component for building modern UIs. This component is part of the tables collection.

### Core Information

- **Component ID**: `table-08`
- **Location**: `/src/lib/components/tables/table-08.svelte`
- **Type**: UI Component

### Usage

```svelte
Full component implementation:

```svelte
<script lang="ts">
	import Checkbox from '$lib/components/ui/checkbox.svelte';

	import {
		Table,
		TableBody,
		TableCell,
		TableFooter,
		TableHead,
		TableHeader,
		TableRow
	} from '$lib/components/ui/table';

	const items = [
		{
			balance: '$1,250.00',
			email: 'alex.t@company.com',
			id: '1',
			location: 'San Francisco, US',
			name: 'Alex Thompson',
			status: 'Active'
		},
		{
			balance: '$600.00',
			email: 'sarah.c@company.com',
			id: '2',
			location: 'Singapore',
			name: 'Sarah Chen',
			status: 'Active'
		},
		{
			balance: '$650.00',
			email: 'j.wilson@company.com',
			id: '3',
			location: 'London, UK',
			name: 'James Wilson',
			status: 'Inactive'
		},
		{
			balance: '$0.00',
			email: 'm.garcia@company.com',
			id: '4',
			location: 'Madrid, Spain',
			name: 'Maria Garcia',
			status: 'Active'
		},
		{
			balance: '-$1,000.00',
			email: 'd.kim@company.com',
			id: '5',
			location: 'Seoul, KR',
			name: 'David Kim',
			status: 'Active'
		}
	];

	const id = $props.id();
</script>

<div>
	<div class="overflow-hidden rounded-md border bg-background">
		<Table>
			<TableHeader>
				<TableRow class="hover:bg-transparent">
					<TableHead class="h-11">
						<Checkbox {id} />
					</TableHead>
					<TableHead class="h-11">Name</TableHead>
					<TableHead class="h-11">Email</TableHead>
					<TableHead class="h-11">Location</TableHead>
					<TableHead class="h-11">Status</TableHead>
					<TableHead class="h-11 text-right">Balance</TableHead>
				</TableRow>
			</TableHeader>
			<TableBody>
				{#each items as item (item.id)}
					<TableRow>
						<TableCell>
							<Checkbox id="table-checkbox-{item.id}" />
						</TableCell>
						<TableCell class="font-medium">{item.name}</TableCell>
						<TableCell>{item.email}</TableCell>
						<TableCell>{item.location}</TableCell>
						<TableCell>{item.status}</TableCell>
						<TableCell class="text-right">{item.balance}</TableCell>
					</TableRow>
				{/each}
			</TableBody>
			<TableFooter class="bg-transparent">
				<TableRow class="hover:bg-transparent">
					<TableCell colspan={5}>Total</TableCell>
					<TableCell class="text-right">$2,500.00</TableCell>
				</TableRow>
			</TableFooter>
		</Table>
	</div>
	<p class="mt-4 text-center text-sm text-muted-foreground">Card Table</p>
</div>

```

### Links

- [View Source](https://github.com/max-got/originui-svelte/tree/main/src/lib/components/tables/table-08.svelte)


## table-09

> A type-safe, accessible table-09 component for building modern UIs. This component is part of the tables collection.

### Core Information

- **Component ID**: `table-09`
- **Location**: `/src/lib/components/tables/table-09.svelte`
- **Type**: UI Component

### Usage

```svelte
Full component implementation:

```svelte
<script lang="ts">
	import { Table, TableBody, TableCell, TableRow } from '$lib/components/ui/table';
</script>

<div class="mx-auto max-w-lg">
	<div class="overflow-hidden rounded-md border bg-background">
		<Table>
			<TableBody>
				<TableRow class="*:border-border hover:bg-transparent [&>:not(:last-child)]:border-r">
					<TableCell class="bg-muted/50 py-2 font-medium">Name</TableCell>
					<TableCell class="py-2">David Kim</TableCell>
				</TableRow>
				<TableRow class="*:border-border hover:bg-transparent [&>:not(:last-child)]:border-r">
					<TableCell class="bg-muted/50 py-2 font-medium">Email</TableCell>
					<TableCell class="py-2">d.kim@company.com</TableCell>
				</TableRow>
				<TableRow class="*:border-border hover:bg-transparent [&>:not(:last-child)]:border-r">
					<TableCell class="bg-muted/50 py-2 font-medium">Location</TableCell>
					<TableCell class="py-2">Seoul, KR</TableCell>
				</TableRow>
				<TableRow class="*:border-border hover:bg-transparent [&>:not(:last-child)]:border-r">
					<TableCell class="bg-muted/50 py-2 font-medium">Status</TableCell>
					<TableCell class="py-2">Active</TableCell>
				</TableRow>
				<TableRow class="*:border-border hover:bg-transparent [&>:not(:last-child)]:border-r">
					<TableCell class="bg-muted/50 py-2 font-medium">Balance</TableCell>
					<TableCell class="py-2">$1,000.00</TableCell>
				</TableRow>
			</TableBody>
		</Table>
	</div>
	<p class="mt-4 text-center text-sm text-muted-foreground">Vertical table</p>
</div>

```

### Links

- [View Source](https://github.com/max-got/originui-svelte/tree/main/src/lib/components/tables/table-09.svelte)


## table-10

> A type-safe, accessible table-10 component for building modern UIs. This component is part of the tables collection.

### Core Information

- **Component ID**: `table-10`
- **Location**: `/src/lib/components/tables/table-10.svelte`
- **Type**: UI Component

### Usage

```svelte
Full component implementation:

```svelte
<script lang="ts">
	import {
		Table,
		TableBody,
		TableCell,
		TableFooter,
		TableHead,
		TableHeader,
		TableRow
	} from '$lib/components/ui/table';

	const items = [
		{
			balance: '$1,250.00',
			email: 'alex.t@company.com',
			id: '1',
			location: 'San Francisco, US',
			name: 'Alex Thompson',
			status: 'Active'
		},
		{
			balance: '$600.00',
			email: 'sarah.c@company.com',
			id: '2',
			location: 'Singapore',
			name: 'Sarah Chen',
			status: 'Active'
		},
		{
			balance: '$650.00',
			email: 'j.wilson@company.com',
			id: '3',
			location: 'London, UK',
			name: 'James Wilson',
			status: 'Inactive'
		},
		{
			balance: '$0.00',
			email: 'm.garcia@company.com',
			id: '4',
			location: 'Madrid, Spain',
			name: 'Maria Garcia',
			status: 'Active'
		},
		{
			balance: '-$1,000.00',
			email: 'd.kim@company.com',
			id: '5',
			location: 'Seoul, KR',
			name: 'David Kim',
			status: 'Active'
		},
		{
			balance: '$1,500.00',
			email: 'john.brown@company.com',
			id: '6',
			location: 'New York, US',
			name: 'John Brown',
			status: 'Active'
		},
		{
			balance: '$200.00',
			email: 'jane.doe@company.com',
			id: '7',
			location: 'Paris, FR',
			name: 'Jane Doe',
			status: 'Inactive'
		},
		{
			balance: '$1,000.00',
			email: 'peter.smith@company.com',
			id: '8',
			location: 'Berlin, DE',
			name: 'Peter Smith',
			status: 'Active'
		},
		{
			balance: '$500.00',
			email: 'olivia.lee@company.com',
			id: '9',
			location: 'Tokyo, JP',
			name: 'Olivia Lee',
			status: 'Active'
		},
		{
			balance: '$300.00',
			email: 'liam.chen@company.com',
			id: '10',
			location: 'Shanghai, CN',
			name: 'Liam Chen',
			status: 'Inactive'
		},
		{
			balance: '$800.00',
			email: 'ethan.kim@company.com',
			id: '11',
			location: 'Busan, KR',
			name: 'Ethan Kim',
			status: 'Active'
		},
		{
			balance: '$1,200.00',
			email: 'ava.brown@company.com',
			id: '12',
			location: 'London, UK',
			name: 'Ava Brown',
			status: 'Active'
		},
		{
			balance: '$400.00',
			email: 'lily.lee@company.com',
			id: '13',
			location: 'Seoul, KR',
			name: 'Lily Lee',
			status: 'Active'
		},
		{
			balance: '$600.00',
			email: 'noah.smith@company.com',
			id: '14',
			location: 'New York, US',
			name: 'Noah Smith',
			status: 'Inactive'
		},
		{
			balance: '$1,800.00',
			email: 'eve.chen@company.com',
			id: '15',
			location: 'Taipei, TW',
			name: 'Eve Chen',
			status: 'Active'
		}
	];
</script>

<div>
	<div class="[&>div]:max-h-96">
		<Table
			class="border-separate border-spacing-0 [&_td]:border-border [&_tfoot_td]:border-t [&_th]:border-b [&_th]:border-border [&_tr:not(:last-child)_td]:border-b [&_tr]:border-none"
		>
			<TableHeader class="backdrop-blur-xs sticky top-0 z-10 bg-background/90">
				<TableRow class="hover:bg-transparent">
					<TableHead>Name</TableHead>
					<TableHead>Email</TableHead>
					<TableHead>Location</TableHead>
					<TableHead>Status</TableHead>
					<TableHead class="text-right">Balance</TableHead>
				</TableRow>
			</TableHeader>
			<TableBody>
				{#each items as item (item.id)}
					<TableRow>
						<TableCell class="font-medium">{item.name}</TableCell>
						<TableCell>{item.email}</TableCell>
						<TableCell>{item.location}</TableCell>
						<TableCell>{item.status}</TableCell>
						<TableCell class="text-right">{item.balance}</TableCell>
					</TableRow>
				{/each}
			</TableBody>
			<TableFooter class="bg-transparent">
				<TableRow class="hover:bg-transparent">
					<TableCell colspan={4}>Total</TableCell>
					<TableCell class="text-right">$2,500.00</TableCell>
				</TableRow>
			</TableFooter>
		</Table>
	</div>
	<p class="mt-8 text-center text-sm text-muted-foreground">Table with sticky header</p>
</div>

```

### Links

- [View Source](https://github.com/max-got/originui-svelte/tree/main/src/lib/components/tables/table-10.svelte)


## table-11

> A type-safe, accessible table-11 component for building modern UIs. This component is part of the tables collection.

### Core Information

- **Component ID**: `table-11`
- **Location**: `/src/lib/components/tables/table-11.svelte`
- **Type**: UI Component

### Usage

```svelte
### Dependencies

Required packages and components:

- [`lucide-svelte`](https://github.com/lucide-icons/lucide)

Full component implementation:

```svelte
<script lang="ts">
	import {
		Table,
		TableBody,
		TableCell,
		TableHead,
		TableHeader,
		TableRow
	} from '$lib/components/ui/table';
	import Check from 'lucide-svelte/icons/check';
	import Monitor from 'lucide-svelte/icons/monitor';
	import Smartphone from 'lucide-svelte/icons/smartphone';
	import X from 'lucide-svelte/icons/x';

	const items = [
		{
			desktop: [
				{ name: 'Chrome', supported: true, version: '115' },
				{ name: 'Edge', supported: true, version: '115' },
				{ name: 'Firefox', supported: false, version: '111' },
				{ name: 'Opera', supported: true, version: '101' },
				{ name: 'Safari', supported: false, version: 'No' }
			],
			feature: 'scroll-timeline',
			mobile: [
				{ name: 'Chrome Android', supported: true, version: '115' },
				{ name: 'Firefox Android', supported: false, version: 'No' },
				{ name: 'Opera Android', supported: true, version: '77' },
				{ name: 'Safari iOS', supported: false, version: 'No' },
				{ name: 'Samsung Internet', supported: true, version: '23' }
			]
		},
		{
			desktop: [
				{ name: 'Chrome', supported: true, version: '115' },
				{ name: 'Edge', supported: true, version: '115' },
				{ name: 'Firefox', supported: false, version: '114' },
				{ name: 'Opera', supported: true, version: '101' },
				{ name: 'Safari', supported: false, version: 'No' }
			],
			feature: 'view-timeline',
			mobile: [
				{ name: 'Chrome Android', supported: true, version: '115' },
				{ name: 'Firefox Android', supported: false, version: 'No' },
				{ name: 'Opera Android', supported: true, version: '77' },
				{ name: 'Safari iOS', supported: false, version: 'No' },
				{ name: 'Samsung Internet', supported: true, version: '23' }
			]
		},
		{
			desktop: [
				{ name: 'Chrome', supported: true, version: '127' },
				{ name: 'Edge', supported: true, version: '127' },
				{ name: 'Firefox', supported: false, version: '3' },
				{ name: 'Opera', supported: true, version: '113' },
				{ name: 'Safari', supported: true, version: '16.4' }
			],
			feature: 'font-size-adjust',
			mobile: [
				{ name: 'Chrome Android', supported: true, version: '127' },
				{ name: 'Firefox Android', supported: true, version: '4' },
				{ name: 'Opera Android', supported: true, version: '84' },
				{ name: 'Safari iOS', supported: true, version: '16.4' },
				{ name: 'Samsung Internet', supported: false, version: 'No' }
			]
		}
	];
</script>

<Table>
	<TableHeader>
		<TableRow
			class="border-y-0 *:border-border hover:bg-transparent [&>:not(:last-child)]:border-r"
		>
			<TableCell></TableCell>
			<TableHead class="border-b text-center" colspan={5}>
				<Monitor class="inline-flex" size={16} aria-hidden="true" />
				<span class="sr-only">Desktop browsers</span>
			</TableHead>
			<TableHead class="border-b text-center" colspan={5}>
				<Smartphone class="inline-flex" size={16} aria-hidden="true" />
				<span class="sr-only">Mobile browsers</span>
			</TableHead>
		</TableRow>
	</TableHeader>
	<TableHeader>
		<TableRow class="*:border-border hover:bg-transparent [&>:not(:last-child)]:border-r">
			<TableCell></TableCell>
			{#each items[0].desktop as browser (browser.name)}
				<TableHead class="h-auto py-3 align-bottom text-foreground">
					<span
						class="relative left-[calc(50%-.5rem)] block rotate-180 whitespace-nowrap leading-4 [text-orientation:sideways] [writing-mode:vertical-rl]"
					>
						{browser.name}
					</span>
				</TableHead>
			{/each}
			{#each items[0].mobile as browser (browser.name)}
				<TableHead class="h-auto py-3 align-bottom text-foreground">
					<span
						class="relative left-[calc(50%-.5rem)] block rotate-180 whitespace-nowrap leading-4 [text-orientation:sideways] [writing-mode:vertical-rl]"
					>
						{browser.name}
					</span>
				</TableHead>
			{/each}
		</TableRow>
	</TableHeader>
	<TableBody>
		{#each items as item (item.feature)}
			<TableRow class="*:border-border [&>:not(:last-child)]:border-r">
				<TableHead class="font-medium text-foreground">
					{item.feature}
				</TableHead>
				{#each [...item.desktop, ...item.mobile] as browser, index (`${browser.name}-${index}`)}
					<TableCell class="space-y-1 text-center">
						{#if browser.supported}
							<Check class="inline-flex stroke-emerald-600" size={16} aria-hidden="true" />
						{:else}
							<X class="inline-flex stroke-red-600" size={16} aria-hidden="true" />
						{/if}
						<span class="sr-only">
							{browser.supported ? 'Supported' : 'Not supported'}
						</span>
						<div class="text-xs font-medium text-muted-foreground">
							{browser.version}
						</div>
					</TableCell>
				{/each}
			</TableRow>
		{/each}
	</TableBody>
</Table>

```

### Links

- [View Source](https://github.com/max-got/originui-svelte/tree/main/src/lib/components/tables/table-11.svelte)


## table-12

> A type-safe, accessible table-12 component for building modern UIs. This component is part of the tables collection.

### Core Information

- **Component ID**: `table-12`
- **Location**: `/src/lib/components/tables/table-12.svelte`
- **Type**: UI Component

### Usage

```svelte
Full component implementation:

```svelte
<script lang="ts">
	import type { User } from '$data/api/data/users.handlers';

	import Badge from '$lib/components/ui/badge.svelte';
	import Checkbox from '$lib/components/ui/checkbox.svelte';

	import { type ColumnDef, getCoreRowModel, type RowSelectionState } from '@tanstack/table-core';
	import { fetchUsers } from '$data/api/data/users';
	import {
		createSvelteTable,
		FlexRender,
		renderComponent,
		renderSnippet
	} from '$lib/components/ui/data-table';
	import {
		Table,
		TableBody,
		TableCell,
		TableFooter,
		TableHead,
		TableHeader,
		TableRow
	} from '$lib/components/ui/table';
	import { cn } from '$lib/utils';
	import { createRawSnippet } from 'svelte';

	const columns: ColumnDef<User>[] = [
		{
			cell: ({ row }) =>
				renderComponent(Checkbox, {
					'aria-label': 'Select row',
					checked: row.getIsSelected(),
					onCheckedChange: (value) => row.toggleSelected(!!value)
				}),
			header: ({ table }) =>
				renderComponent(Checkbox, {
					'aria-label': 'Select all',
					checked: table.getIsAllPageRowsSelected(),
					indeterminate: table.getIsSomePageRowsSelected() && !table.getIsAllPageRowsSelected(),
					onCheckedChange: (value) => table.toggleAllPageRowsSelected(!!value)
				}),
			id: 'select'
		},
		{
			accessorKey: 'name',
			cell: ({ row }) => {
				const nameSnippet = createRawSnippet<[string]>((getName) => {
					const name = getName();
					return {
						render: () => `<div class="font-medium">${name}</div>`
					};
				});
				return renderSnippet(nameSnippet, row.getValue('name'));
			},
			header: 'Name'
		},
		{
			accessorKey: 'email',
			header: 'Email'
		},
		{
			accessorKey: 'location',
			cell: ({ row }) => {
				const locationSnippet = createRawSnippet<[{ flag: string; location: string }]>((args) => {
					const { flag, location } = args();
					return {
						render: () => `
							<div>
								<span class="text-lg leading-none">${flag}</span>
								${location}
							</div>`
					};
				});
				return renderSnippet(locationSnippet, {
					flag: row.original.flag,
					location: row.getValue('location') as string
				});
			},
			header: 'Location'
		},
		{
			accessorKey: 'status',
			cell: ({ row }) =>
				renderComponent(Badge, {
					children: createRawSnippet(() => {
						const status = row.getValue('status') as string;
						return {
							render: () => status
						};
					}),

					class: cn(
						row.getValue('status') === 'Inactive' &&
							'bg-muted-foreground/60 text-primary-foreground'
					)
				}),
			header: 'Status'
		},
		{
			accessorKey: 'balance',
			cell: ({ row }) => {
				return renderSnippet(
					createRawSnippet((getBalance) => {
						const balance = getBalance() as string;
						const formatted = new Intl.NumberFormat('en-US', {
							currency: 'USD',
							style: 'currency'
						}).format(parseFloat(balance));
						return {
							render: () => `<div class="text-right">${formatted}</div>`
						};
					}),
					row.getValue('balance')
				);
			},
			header: () => {
				const nameSnippet = createRawSnippet(() => {
					return {
						render: () => `<div class="text-right">Balance</div>`
					};
				});
				return renderSnippet(nameSnippet, {});
			}
		}
	];

	let rowSelection = $state<RowSelectionState>({});
	let data = $state<User[]>([]);

	$effect(() => {
		fetchUsers()
			.then((response) => {
				data = response.slice(0, 5);
			})
			.catch((err) => {
				console.error(err);
			});
	});

	const table = createSvelteTable<User>({
		columns,
		get data() {
			return data;
		},
		getCoreRowModel: getCoreRowModel(),
		onRowSelectionChange: (updater) => {
			if (typeof updater === 'function') {
				rowSelection = updater(rowSelection);
			} else {
				rowSelection = updater;
			}
		},
		state: {
			get rowSelection() {
				return rowSelection;
			}
		}
	});
</script>

<div>
	<Table>
		<TableHeader>
			{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
				<TableRow class="hover:bg-transparent">
					{#each headerGroup.headers as header (header.id)}
						<TableHead>
							{#if !header.isPlaceholder}
								<FlexRender
									content={header.column.columnDef.header}
									context={header.getContext()}
								/>
							{/if}
						</TableHead>
					{/each}
				</TableRow>
			{/each}
		</TableHeader>
		<TableBody>
			{#each table.getRowModel().rows as row (row.id)}
				<TableRow data-state={row.getIsSelected() && 'selected'}>
					{#each row.getVisibleCells() as cell (cell.id)}
						<TableCell>
							<FlexRender content={cell.column.columnDef.cell} context={cell.getContext()} />
						</TableCell>
					{/each}
				</TableRow>
			{:else}
				<TableRow>
					<TableCell colspan={columns.length} class="h-24 text-center">No results.</TableCell>
				</TableRow>
			{/each}
		</TableBody>
		<TableFooter class="bg-transparent">
			<TableRow class="hover:bg-transparent">
				<TableCell colspan={5}>Total</TableCell>
				<TableCell class="text-right">
					{new Intl.NumberFormat('en-US', {
						currency: 'USD',
						style: 'currency'
					}).format(data.reduce((total, item) => total + item.balance, 0))}
				</TableCell>
			</TableRow>
		</TableFooter>
	</Table>
	<p class="mt-4 text-center text-sm text-muted-foreground">
		Basic data table made with
		<a
			class="underline hover:text-foreground"
			href="https://tanstack.com/table"
			target="_blank"
			rel="noopener noreferrer"
		>
			TanStack Table
		</a>
	</p>
</div>

```

### Links

- [View Source](https://github.com/max-got/originui-svelte/tree/main/src/lib/components/tables/table-12.svelte)


## table-13

> A type-safe, accessible table-13 component for building modern UIs. This component is part of the tables collection.

### Core Information

- **Component ID**: `table-13.todo`
- **Location**: `/src/lib/components/tables/table-13.todo.svelte`
- **Type**: UI Component

### Usage

```svelte
Full component implementation:

```svelte

```

### Links

- [View Source](https://github.com/max-got/originui-svelte/tree/main/src/lib/components/tables/table-13.todo.svelte)


## table-14

> A type-safe, accessible table-14 component for building modern UIs. This component is part of the tables collection.

### Core Information

- **Component ID**: `table-14`
- **Location**: `/src/lib/components/tables/table-14.svelte`
- **Type**: UI Component

### Usage

```svelte
### Dependencies

Required packages and components:

- [`lucide-svelte`](https://github.com/lucide-icons/lucide)

Full component implementation:

```svelte
<script lang="ts">
	import type { User } from '$data/api/data/users.handlers';

	import {
		type ColumnDef,
		type ColumnSizingState,
		getCoreRowModel,
		getSortedRowModel,
		type SortingState
	} from '@tanstack/table-core';
	import { fetchUsers } from '$data/api/data/users';
	import { createSvelteTable, FlexRender, renderSnippet } from '$lib/components/ui/data-table';
	import {
		Table,
		TableBody,
		TableCell,
		TableHead,
		TableHeader,
		TableRow
	} from '$lib/components/ui/table';
	import { cn } from '$lib/utils';
	import ChevronDown from 'lucide-svelte/icons/chevron-down';
	import ChevronUp from 'lucide-svelte/icons/chevron-up';
	import { createRawSnippet } from 'svelte';

	const columns: ColumnDef<User>[] = [
		{
			accessorKey: 'name',
			cell: ({ row }) => {
				const nameSnippet = createRawSnippet<[string]>((getName) => {
					const name = getName();
					return {
						render: () => `<div class="truncate font-medium">${name}</div>`
					};
				});
				return renderSnippet(nameSnippet, row.getValue('name'));
			},
			header: 'Name',
			sortDescFirst: false,
			sortUndefined: 'last'
		},
		{
			accessorKey: 'email',
			header: 'Email'
		},
		{
			accessorKey: 'location',
			cell: ({ row }) => {
				const locationSnippet = createRawSnippet<[{ flag: string; location: string }]>((args) => {
					const { flag, location } = args();
					return {
						render: () => `
							<div>
								<span class="text-lg leading-none">${flag}</span>
								${location}
							</div>`
					};
				});
				return renderSnippet(locationSnippet, {
					flag: row.original.flag,
					location: row.getValue('location') as string
				});
			},
			header: 'Location'
		},
		{
			accessorKey: 'status',
			header: 'Status'
		},
		{
			accessorKey: 'balance',
			cell: ({ row }) => {
				const amount = parseFloat(row.getValue('balance'));
				const formatted = new Intl.NumberFormat('en-US', {
					currency: 'USD',
					style: 'currency'
				}).format(amount);
				return formatted;
			},
			header: 'Balance'
		},
		{
			accessorKey: 'department',
			header: 'Department'
		},
		{
			accessorKey: 'role',
			header: 'Role'
		},
		{
			accessorKey: 'joinDate',
			header: 'Join Date'
		},
		{
			accessorKey: 'lastActive',
			header: 'Last Active'
		},
		{
			accessorKey: 'performance',
			header: 'Performance'
		}
	];

	let sorting = $state<SortingState>([
		{
			desc: false,
			id: 'name'
		}
	]);
	let columnSizing = $state<ColumnSizingState>({});
	let data = $state<User[]>([]);

	$effect(() => {
		fetchUsers()
			.then((response) => {
				data = response.slice(0, 5);
			})
			.catch((err) => {
				console.error(err);
			});
	});

	const table = createSvelteTable<User>({
		columnResizeMode: 'onChange',
		columns,
		get data() {
			return data;
		},
		getCoreRowModel: getCoreRowModel(),
		getSortedRowModel: getSortedRowModel(),
		onColumnSizingChange: (updater) => {
			if (typeof updater === 'function') {
				columnSizing = updater(columnSizing);
			} else {
				columnSizing = updater;
			}
		},
		onSortingChange: (updater) => {
			if (typeof updater === 'function') {
				sorting = updater(sorting);
			} else {
				sorting = updater;
			}
		},
		state: {
			get columnSizing() {
				return columnSizing;
			},
			get sorting() {
				return sorting;
			}
		}
	});
</script>

<div>
	<Table class="table-fixed" style="width: {table.getCenterTotalSize()}px">
		<TableHeader>
			{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
				<TableRow class="bg-muted/50">
					{#each headerGroup.headers as header (header.id)}
						<TableHead
							class="relative h-10 select-none border-t [&:last-child>.cursor-col-resize]:opacity-0"
							aria-sort={header.column.getIsSorted() === 'asc'
								? 'ascending'
								: header.column.getIsSorted() === 'desc'
									? 'descending'
									: 'none'}
							colspan={header.colSpan}
							style="width: {header.getSize()}px"
						>
							{#if !header.isPlaceholder}
								<div
									class={cn(
										header.column.getCanSort() &&
											'flex h-full cursor-pointer select-none items-center justify-between gap-2'
									)}
									onclick={header.column.getToggleSortingHandler()}
									onkeydown={(e) => {
										// Enhanced keyboard handling for sorting
										if (header.column.getCanSort() && (e.key === 'Enter' || e.key === ' ')) {
											e.preventDefault();
											header.column.getToggleSortingHandler()?.(e);
										}
									}}
									tabindex={header.column.getCanSort() ? 0 : undefined}
								>
									<span class="truncate">
										<FlexRender
											content={header.column.columnDef.header}
											context={header.getContext()}
										/>
									</span>
									{#if header.column.getIsSorted() === 'asc'}
										<ChevronUp class="shrink-0 opacity-60" size={16} aria-hidden="true" />
									{:else if header.column.getIsSorted() === 'desc'}
										<ChevronDown class="shrink-0 opacity-60" size={16} aria-hidden="true" />
									{/if}
								</div>
							{/if}
							{#if header.column.getCanResize()}
								<div
									class="user-select-none absolute -right-2 top-0 z-10 flex h-full w-4 cursor-col-resize touch-none justify-center before:absolute before:inset-y-0 before:w-px before:translate-x-px before:bg-border"
									ondblclick={() => header.column.resetSize()}
									onmousedown={header.getResizeHandler()}
									ontouchstart={header.getResizeHandler()}
								/>
							{/if}
						</TableHead>
					{/each}
				</TableRow>
			{/each}
		</TableHeader>
		<TableBody>
			{#each table.getRowModel().rows as row (row.id)}
				<TableRow data-state={row.getIsSelected() && 'selected'}>
					{#each row.getVisibleCells() as cell (cell.id)}
						<TableCell class="truncate">
							<FlexRender content={cell.column.columnDef.cell} context={cell.getContext()} />
						</TableCell>
					{/each}
				</TableRow>
			{:else}
				<TableRow>
					<TableCell colspan={columns.length} class="h-24 text-center">No results.</TableCell>
				</TableRow>
			{/each}
		</TableBody>
	</Table>
	<p class="mt-4 text-center text-sm text-muted-foreground">
		Resizable and sortable columns made with
		<a
			class="underline hover:text-foreground"
			href="https://tanstack.com/table"
			target="_blank"
			rel="noopener noreferrer"
		>
			TanStack Table
		</a>
	</p>
</div>

```

### Links

- [View Source](https://github.com/max-got/originui-svelte/tree/main/src/lib/components/tables/table-14.svelte)


## table-15

> A type-safe, accessible table-15 component for building modern UIs. This component is part of the tables collection.

### Core Information

- **Component ID**: `table-15`
- **Location**: `/src/lib/components/tables/table-15.svelte`
- **Type**: UI Component

### Usage

```svelte
### Dependencies

Required packages and components:

- [`lucide-svelte`](https://github.com/lucide-icons/lucide)

Full component implementation:

```svelte
<script lang="ts">
	import type { User } from '$data/api/data/users.handlers';
	import type { HTMLAttributes } from 'svelte/elements';

	import Button from '$lib/components/ui/button.svelte';

	import {
		type Column,
		type ColumnDef,
		type ColumnPinningState,
		type ColumnSizingState,
		getCoreRowModel,
		getSortedRowModel,
		type SortingState
	} from '@tanstack/table-core';
	import { fetchUsers } from '$data/api/data/users';
	import { createSvelteTable, FlexRender, renderSnippet } from '$lib/components/ui/data-table';
	import {
		DropdownMenu,
		DropdownMenuContent,
		DropdownMenuItem,
		DropdownMenuTrigger
	} from '$lib/components/ui/dropdowns';
	import {
		Table,
		TableBody,
		TableCell,
		TableHead,
		TableHeader,
		TableRow
	} from '$lib/components/ui/table';
	import ArrowLeftToLineIcon from 'lucide-svelte/icons/arrow-left-to-line';
	import ArrowRightToLineIcon from 'lucide-svelte/icons/arrow-right-to-line';
	import EllipsisIcon from 'lucide-svelte/icons/ellipsis';
	import PinOffIcon from 'lucide-svelte/icons/pin-off';
	import { createRawSnippet } from 'svelte';

	let sorting = $state<SortingState>([
		{
			desc: false,
			id: 'name'
		}
	]);

	// Helper function to compute pinning styles for columns
	function getPinningStyles(column: Column<User>): HTMLAttributes<HTMLTableCellElement>['style'] {
		const isPinned = column.getIsPinned();
		const properties = {
			left: isPinned === 'left' ? `${column.getStart('left')}px` : undefined,
			position: isPinned ? 'sticky' : 'relative',
			right: isPinned === 'right' ? `${column.getAfter('right')}px` : undefined,
			width: column.getSize() + 'px',
			'z-index': isPinned ? 1 : 0
		};

		return Object.entries(properties)
			.filter(([, value]) => value !== undefined)
			.map(([key, value]) => `${key}: ${value}`)
			.join(';');
	}

	const columns: ColumnDef<User>[] = [
		{
			accessorKey: 'name',
			cell: ({ row }) => {
				const nameSnippet = createRawSnippet<[string]>((getName) => {
					const name = getName();
					return {
						render: () => `<div class="truncate font-medium">${name}</div>`
					};
				});
				return renderSnippet(nameSnippet, row.getValue('name'));
			},
			header: 'Name'
		},
		{
			accessorKey: 'email',
			header: 'Email'
		},
		{
			accessorKey: 'location',
			cell: ({ row }) => {
				const locationSnippet = createRawSnippet<[{ flag: string; location: string }]>((args) => {
					const { flag, location } = args();
					return {
						render: () => `
							<div>
								<span class="text-lg leading-none">${flag}</span>
								${location}
							</div>`
					};
				});
				return renderSnippet(locationSnippet, {
					flag: row.original.flag,
					location: row.getValue('location') as string
				});
			},
			header: 'Location'
		},
		{
			accessorKey: 'status',
			header: 'Status'
		},
		{
			accessorKey: 'balance',
			cell: ({ row }) => {
				const amount = parseFloat(row.getValue('balance'));
				const formatted = new Intl.NumberFormat('en-US', {
					currency: 'USD',
					style: 'currency'
				}).format(amount);
				return formatted;
			},
			header: 'Balance'
		},
		{
			accessorKey: 'department',
			header: 'Department'
		},
		{
			accessorKey: 'role',
			header: 'Role'
		},
		{
			accessorKey: 'joinDate',
			header: 'Join Date'
		},
		{
			accessorKey: 'lastActive',
			header: 'Last Active'
		},
		{
			accessorKey: 'performance',
			header: 'Performance'
		}
	];

	let columnSizing = $state<ColumnSizingState>({});
	let columnPinning = $state<ColumnPinningState>({});
	let data = $state<User[]>([]);

	$effect(() => {
		fetchUsers()
			.then((response) => {
				data = response.slice(0, 5);
			})
			.catch((err) => {
				console.error(err);
			});
	});

	const table = createSvelteTable<User>({
		columnResizeMode: 'onChange',
		columns,
		get data() {
			return data;
		},
		enableSortingRemoval: false,

		getCoreRowModel: getCoreRowModel(),
		getSortedRowModel: getSortedRowModel(),
		onColumnPinningChange: (updater) => {
			if (typeof updater === 'function') {
				columnPinning = updater(columnPinning);
			} else {
				columnPinning = updater;
			}
		},
		onColumnSizingChange: (updater) => {
			if (typeof updater === 'function') {
				columnSizing = updater(columnSizing);
			} else {
				columnSizing = updater;
			}
		},
		onSortingChange: (updater) => {
			if (typeof updater === 'function') {
				sorting = updater(sorting);
			} else {
				sorting = updater;
			}
		},
		state: {
			get columnPinning() {
				return columnPinning;
			},
			get columnSizing() {
				return columnSizing;
			},
			get sorting() {
				return sorting;
			}
		}
	});
</script>

<div>
	<Table
		class="table-fixed border-separate border-spacing-0 [&_td]:border-border [&_tfoot_td]:border-t [&_th]:border-b [&_th]:border-border [&_tr:not(:last-child)_td]:border-b [&_tr]:border-none"
		style="width: {table.getCenterTotalSize()}px"
	>
		<TableHeader>
			{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
				<TableRow class="bg-muted/50">
					{#each headerGroup.headers as header (header.id)}
						{@const isPinned = header.column.getIsPinned()}
						{@const isLastLeftPinned = isPinned === 'left' && header.column.getIsLastColumn('left')}
						{@const isFirstRightPinned =
							isPinned === 'right' && header.column.getIsFirstColumn('right')}

						<TableHead
							class="data-pinned:bg-muted/90 data-pinned:backdrop-blur-xs relative h-10 truncate border-t [&:not([data-pinned]):has(+[data-pinned])_div.cursor-col-resize:last-child]:opacity-0 [&[data-last-col=left]_div.cursor-col-resize:last-child]:opacity-0 [&[data-pinned=left][data-last-col=left]]:border-r [&[data-pinned=right]:last-child_div.cursor-col-resize:last-child]:opacity-0 [&[data-pinned=right][data-last-col=right]]:border-l [&[data-pinned][data-last-col]]:border-border"
							aria-sort={header.column.getIsSorted() === 'asc'
								? 'ascending'
								: header.column.getIsSorted() === 'desc'
									? 'descending'
									: 'none'}
							colspan={header.colSpan}
							data-pinned={isPinned || undefined}
							data-last-col={isLastLeftPinned ? 'left' : isFirstRightPinned ? 'right' : undefined}
							style={getPinningStyles(header.column)}
						>
							<div class="flex items-center justify-between gap-2">
								{#if !header.isPlaceholder}
									<span class="truncate">
										<FlexRender
											content={header.column.columnDef.header}
											context={header.getContext()}
										/>
									</span>
								{/if}
								<!-- Pin/Unpin column controls with enhanced accessibility -->
								{#if !header.isPlaceholder && header.column.getCanPin() && header.column.getIsPinned()}
									<Button
										size="icon"
										variant="ghost"
										class="-mr-1 size-7 shadow-none"
										onclick={() => header.column.pin(false)}
										aria-label="Unpin {header.column.columnDef.header} column"
										title="Unpin {header.column.columnDef.header} column"
									>
										<PinOffIcon class="opacity-60" size={16} aria-hidden="true" />
									</Button>
								{:else}
									<DropdownMenu>
										<DropdownMenuTrigger>
											{#snippet child({ props })}
												<Button
													size="icon"
													variant="ghost"
													class="-mr-1 size-7 shadow-none"
													aria-label="Pin options for {header.column.columnDef.header} column"
													title="Pin options for {header.column.columnDef.header} column"
													{...props}
												>
													<EllipsisIcon class="opacity-60" size={16} aria-hidden="true" />
												</Button>
											{/snippet}
										</DropdownMenuTrigger>
										<DropdownMenuContent align="end">
											<DropdownMenuItem onclick={() => header.column.pin('left')}>
												<ArrowLeftToLineIcon size={16} class="opacity-60" aria-hidden="true" />
												Stick to left
											</DropdownMenuItem>
											<DropdownMenuItem onclick={() => header.column.pin('right')}>
												<ArrowRightToLineIcon size={16} class="opacity-60" aria-hidden="true" />
												Stick to right
											</DropdownMenuItem>
										</DropdownMenuContent>
									</DropdownMenu>
								{/if}
								{#if header.column.getCanResize()}
									<div
										class="user-select-none absolute -right-2 top-0 z-10 flex h-full w-4 cursor-col-resize touch-none justify-center before:absolute before:inset-y-0 before:w-px before:-translate-x-px before:bg-border"
										ondblclick={() => header.column.resetSize()}
										onmousedown={header.getResizeHandler()}
										ontouchstart={header.getResizeHandler()}
									/>
								{/if}
							</div>
						</TableHead>
					{/each}
				</TableRow>
			{/each}
		</TableHeader>
		<TableBody>
			{#each table.getRowModel().rows as row (row.id)}
				<TableRow data-state={row.getIsSelected() && 'selected'}>
					{#each row.getVisibleCells() as cell (cell.id)}
						{@const isPinned = cell.column.getIsPinned()}
						{@const isLastLeftPinned = isPinned === 'left' && cell.column.getIsLastColumn('left')}
						{@const isFirstRightPinned =
							isPinned === 'right' && cell.column.getIsFirstColumn('right')}

						<TableCell
							class="data-pinned:bg-background/90 data-pinned:backdrop-blur-xs truncate [&[data-pinned=left][data-last-col=left]]:border-r [&[data-pinned=right][data-last-col=right]]:border-l [&[data-pinned][data-last-col]]:border-border"
							style={getPinningStyles(cell.column)}
							data-pinned={isPinned || undefined}
							data-last-col={isLastLeftPinned ? 'left' : isFirstRightPinned ? 'right' : undefined}
						>
							<FlexRender content={cell.column.columnDef.cell} context={cell.getContext()} />
						</TableCell>
					{/each}
				</TableRow>
			{:else}
				<TableRow>
					<TableCell colspan={columns.length} class="h-24 text-center">No results.</TableCell>
				</TableRow>
			{/each}
		</TableBody>
	</Table>
	<p class="mt-4 text-center text-sm text-muted-foreground">
		Pinnable columns made with
		<a
			class="underline hover:text-foreground"
			href="https://tanstack.com/table"
			target="_blank"
			rel="noopener noreferrer"
		>
			TanStack Table
		</a>
	</p>
</div>

```

### Links

- [View Source](https://github.com/max-got/originui-svelte/tree/main/src/lib/components/tables/table-15.svelte)


## table-16

> A type-safe, accessible table-16 component for building modern UIs. This component is part of the tables collection.

### Core Information

- **Component ID**: `table-16`
- **Location**: `/src/lib/components/tables/table-16.svelte`
- **Type**: UI Component

### Usage

```svelte
### Dependencies

Required packages and components:

- [`@dnd-kit-svelte/core`](https://github.com/HanielU/dnd-kit-svelte)
- [`@dnd-kit-svelte/modifiers`](https://github.com/HanielU/dnd-kit-svelte)
- [`@dnd-kit-svelte/sortable`](https://github.com/HanielU/dnd-kit-svelte)
- [`@dnd-kit-svelte/utilities`](https://github.com/HanielU/dnd-kit-svelte)
- [`lucide-svelte`](https://github.com/lucide-icons/lucide)

Full component implementation:

```svelte
<script lang="ts">
	import type { User } from '$data/api/data/users.handlers';

	import Button from '$lib/components/ui/button.svelte';

	import {
		closestCenter,
		DndContext,
		type DragEndEvent,
		KeyboardSensor,
		MouseSensor,
		TouchSensor,
		useSensor,
		useSensors
	} from '@dnd-kit-svelte/core';
	import { restrictToHorizontalAxis } from '@dnd-kit-svelte/modifiers';
	import {
		arrayMove,
		horizontalListSortingStrategy,
		SortableContext,
		useSortable
	} from '@dnd-kit-svelte/sortable';
	import { CSS } from '@dnd-kit-svelte/utilities';
	import {
		type Cell,
		type ColumnDef,
		getCoreRowModel,
		getSortedRowModel,
		type Header,
		type SortingState
	} from '@tanstack/table-core';
	import { fetchUsers } from '$data/api/data/users';
	import { createSvelteTable, FlexRender, renderSnippet } from '$lib/components/ui/data-table';
	import {
		Table,
		TableBody,
		TableCell,
		TableHead,
		TableHeader,
		TableRow
	} from '$lib/components/ui/table';
	import ChevronDown from 'lucide-svelte/icons/chevron-down';
	import ChevronUp from 'lucide-svelte/icons/chevron-up';
	import GripVertical from 'lucide-svelte/icons/grip-vertical';
	import { createRawSnippet } from 'svelte';

	const columns: ColumnDef<User>[] = [
		{
			accessorKey: 'name',
			cell: ({ row }) => {
				const nameSnippet = createRawSnippet<[string]>((getName) => {
					const name = getName();
					return {
						render: () => `<div class="truncate font-medium">${name}</div>`
					};
				});
				return renderSnippet(nameSnippet, row.getValue('name'));
			},
			header: 'Name',
			id: 'name',
			sortDescFirst: false,
			sortUndefined: 'last'
		},
		{
			accessorKey: 'email',
			header: 'Email',
			id: 'email'
		},
		{
			accessorKey: 'location',
			cell: ({ row }) => {
				const locationSnippet = createRawSnippet<[{ flag: string; location: string }]>((args) => {
					const { flag, location } = args();
					return {
						render: () => `
							<div class="truncate">
								<span class="text-lg leading-none">${flag}</span>
								${location}
							</div>`
					};
				});
				return renderSnippet(locationSnippet, {
					flag: row.original.flag,
					location: row.getValue('location') as string
				});
			},
			header: 'Location',
			id: 'location'
		},
		{
			accessorKey: 'status',
			header: 'Status',
			id: 'status'
		},
		{
			accessorKey: 'balance',
			cell: ({ row }) => {
				const amount = parseFloat(row.getValue('balance'));
				const formatted = new Intl.NumberFormat('en-US', {
					currency: 'USD',
					style: 'currency'
				}).format(amount);
				return formatted;
			},
			header: 'Balance',
			id: 'balance'
		}
	];

	let data = $state<User[]>([]);
	let sorting = $state<SortingState>([
		{
			desc: false,
			id: 'name'
		}
	]);
	let columnOrder = $state<string[]>(columns.map((column) => column.id ?? ''));

	$effect(() => {
		fetchUsers()
			.then((response) => {
				data = response.slice(0, 5);
			})
			.catch((err) => {
				console.error(err);
			});
	});

	const table = createSvelteTable<User>({
		columnResizeMode: 'onChange',
		columns,
		get data() {
			return data;
		},
		enableSortingRemoval: false,
		getCoreRowModel: getCoreRowModel(),
		getSortedRowModel: getSortedRowModel(),
		onColumnOrderChange: (updater) => {
			if (typeof updater === 'function') {
				columnOrder = updater(columnOrder);
			} else {
				columnOrder = updater;
			}
		},
		onSortingChange: (updater) => {
			if (typeof updater === 'function') {
				sorting = updater(sorting);
			} else {
				sorting = updater;
			}
		},
		state: {
			get columnOrder() {
				return columnOrder;
			},
			get sorting() {
				return sorting;
			}
		}
	});

	// reorder columns after drag & drop
	function handleDragEnd(event: DragEndEvent) {
		const { active, over } = event;
		if (active && over && active.id !== over.id) {
			// this is just a splice util
			columnOrder = arrayMove(
				columnOrder,
				columnOrder.indexOf(active.id as string), // oldIndex
				columnOrder.indexOf(over.id as string) // newIndex
			);
		}
	}

	const sensors = useSensors(
		useSensor(MouseSensor, {}),
		useSensor(TouchSensor, {}),
		useSensor(KeyboardSensor, {})
	);

	let id = $props.id();
</script>

<DndContext
	{id}
	collisionDetection={closestCenter}
	modifiers={[restrictToHorizontalAxis]}
	onDragEnd={handleDragEnd}
	{sensors}
>
	<Table>
		<TableHeader>
			{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
				<TableRow class="bg-muted/50">
					<SortableContext items={columnOrder} strategy={horizontalListSortingStrategy}>
						{#each headerGroup.headers as header (header.id)}
							{@render DraggableTableHeader(header)}
						{/each}
					</SortableContext>
				</TableRow>
			{/each}
		</TableHeader>
		<TableBody>
			{#each table.getRowModel().rows as row (row.id)}
				<TableRow data-state={row.getIsSelected() && 'selected'}>
					{#each row.getVisibleCells() as cell (cell.id)}
						<SortableContext items={columnOrder} strategy={horizontalListSortingStrategy}>
							{@render DragAlongCell(cell)}
						</SortableContext>
					{/each}
				</TableRow>
			{:else}
				<TableRow>
					<TableCell colspan={columns.length} class="h-24 text-center">No results.</TableCell>
				</TableRow>
			{/each}
		</TableBody>
	</Table>
	<p class="mt-4 text-center text-sm text-muted-foreground">
		Draggable columns made with
		<a
			class="underline hover:text-foreground"
			href="https://tanstack.com/table"
			target="_blank"
			rel="noopener noreferrer"
		>
			TanStack Table
		</a>
		and
		<a href="https://dnd-kit-svelte.vercel.app/" target="_blank" rel="noopener noreferrer">
			dnd kit
		</a>
	</p>
</DndContext>

{#snippet DraggableTableHeader(header: Header<User, unknown>)}
	{@const { attributes, isDragging, listeners, setNodeRef, transform, transition } = useSortable({
		id: header.column.id
	})}
	{@const style = `opacity: ${isDragging.current ? 0.8 : 1}; position: relative; transform: ${CSS.Translate.toString(transform.current)}; transition: ${transition.current ?? 'initial'}; whiteSpace: nowrap; width: ${header.column.getSize()}px; z-index: ${isDragging.current ? 1 : 0}`}

	<TableHead
		ref={setNodeRef as unknown as HTMLElement}
		class="relative h-10 border-t before:absolute before:inset-y-0 before:start-0 before:w-px before:bg-border first:before:bg-transparent"
		{style}
		aria-sort={header.column.getIsSorted() === 'asc'
			? 'ascending'
			: header.column.getIsSorted() === 'desc'
				? 'descending'
				: 'none'}
	>
		<div class="flex items-center justify-start gap-0.5">
			<Button
				size="icon"
				variant="ghost"
				class="-ml-2 size-7 shadow-none"
				{...attributes.current}
				{...listeners.current}
				aria-label="Drag to reorder"
			>
				<GripVertical class="opacity-60" size={16} aria-hidden="true" />
			</Button>
			<span class="grow truncate">
				{#if !header.isPlaceholder}
					<FlexRender content={header.column.columnDef.header} context={header.getContext()} />
				{/if}
			</span>
			<Button
				size="icon"
				variant="ghost"
				class="group -mr-1 size-7 shadow-none"
				onclick={header.column.getToggleSortingHandler()}
				onkeydown={(e: KeyboardEvent) => {
					// Enhanced keyboard handling for sorting
					if (header.column.getCanSort() && (e.key === 'Enter' || e.key === ' ')) {
						e.preventDefault();
						header.column.getToggleSortingHandler()?.(e);
					}
				}}
			>
				{#if header.column.getIsSorted() === 'asc'}
					<ChevronUp class="shrink-0 opacity-60" size={16} aria-hidden="true" />
				{:else if header.column.getIsSorted() === 'desc'}
					<ChevronDown class="shrink-0 opacity-60" size={16} aria-hidden="true" />
				{:else if header.column.getIsSorted() === false}
					<ChevronUp
						class="shrink-0 opacity-0 group-hover:opacity-60"
						size={16}
						aria-hidden="true"
					/>
				{/if}
			</Button>
		</div>
	</TableHead>
{/snippet}

{#snippet DragAlongCell(cell: Cell<User, unknown>)}
	{@const { isDragging, setNodeRef, transform, transition } = useSortable({ id: cell.column.id })}
	{@const style = `opacity: ${isDragging.current ? 0.8 : 1}; position: relative; transform: ${CSS.Translate.toString(transform.current)}; transition: ${transition.current ?? 'initial'}; width: ${cell.column.getSize()}px; z-index: ${isDragging.current ? 1 : 0}`}
	<TableCell class="truncate" ref={setNodeRef as unknown as HTMLElement} {style}>
		<FlexRender content={cell.column.columnDef.cell} context={cell.getContext()} />
	</TableCell>
{/snippet}

```

### Links

- [View Source](https://github.com/max-got/originui-svelte/tree/main/src/lib/components/tables/table-16.svelte)


## table-17

> A type-safe, accessible table-17 component for building modern UIs. This component is part of the tables collection.

### Core Information

- **Component ID**: `table-17`
- **Location**: `/src/lib/components/tables/table-17.svelte`
- **Type**: UI Component

### Usage

```svelte
### Dependencies

Required packages and components:

- [`lucide-svelte`](https://github.com/lucide-icons/lucide)

Full component implementation:

```svelte
<script lang="ts">
	import type { User } from '$data/api/data/users.handlers';

	import Badge from '$lib/components/ui/badge.svelte';
	import Button from '$lib/components/ui/button.svelte';
	import Checkbox from '$lib/components/ui/checkbox.svelte';

	import {
		type ColumnDef,
		type ExpandedState,
		getCoreRowModel,
		getExpandedRowModel,
		type RowSelectionState
	} from '@tanstack/table-core';
	import { fetchUsers } from '$data/api/data/users';
	import {
		createSvelteTable,
		FlexRender,
		renderComponent,
		renderSnippet
	} from '$lib/components/ui/data-table';
	import {
		Table,
		TableBody,
		TableCell,
		TableHead,
		TableHeader,
		TableRow
	} from '$lib/components/ui/table';
	import { cn } from '$lib/utils';
	import ChevronDown from 'lucide-svelte/icons/chevron-down';
	import ChevronUp from 'lucide-svelte/icons/chevron-up';
	import Info from 'lucide-svelte/icons/info';
	import { createRawSnippet, mount, unmount } from 'svelte';

	const columns: ColumnDef<User>[] = [
		{
			cell: ({ row }) => {
				if (!row.getCanExpand()) return;

				return renderComponent(Button, {
					'aria-expanded': row.getIsExpanded(),
					'aria-label': row.getIsExpanded()
						? `Collapse details for ${row.original.name}`
						: `Expand details for ${row.original.name}`,
					children: createRawSnippet(() => {
						return {
							render: () => '<!---->',
							setup: (target) => {
								const icon = mount(row.getIsExpanded() ? ChevronUp : ChevronDown, {
									props: { 'aria-hidden': true, class: 'opacity-60', size: 16 },
									target: target.parentElement as Element
								});
								return () => unmount(icon);
							}
						};
					}),
					class: 'size-7 shadow-none text-muted-foreground',
					onclick: row.getToggleExpandedHandler(),
					size: 'icon',
					variant: 'ghost'
				});
			},
			header: () => null,
			id: 'expander'
		},
		{
			cell: ({ row }) =>
				renderComponent(Checkbox, {
					'aria-label': 'Select row',
					checked: row.getIsSelected(),
					onCheckedChange: (value) => row.toggleSelected(!!value)
				}),
			header: ({ table }) =>
				renderComponent(Checkbox, {
					'aria-label': 'Select all',
					checked: table.getIsAllPageRowsSelected(),
					indeterminate: table.getIsSomePageRowsSelected() && !table.getIsAllPageRowsSelected(),
					onCheckedChange: (value) => table.toggleAllPageRowsSelected(!!value)
				}),
			id: 'select'
		},
		{
			accessorKey: 'name',
			cell: ({ row }) => {
				const nameSnippet = createRawSnippet<[string]>((getName) => {
					const name = getName();
					return {
						render: () => `<div class="font-medium">${name}</div>`
					};
				});
				return renderSnippet(nameSnippet, row.getValue('name'));
			},
			header: 'Name'
		},
		{
			accessorKey: 'email',
			header: 'Email'
		},
		{
			accessorKey: 'location',
			cell: ({ row }) => {
				const locationSnippet = createRawSnippet<[{ flag: string; location: string }]>((args) => {
					const { flag, location } = args();
					return {
						render: () => `
							<div>
								<span class="text-lg leading-none">${flag}</span>
								${location}
							</div>`
					};
				});
				return renderSnippet(locationSnippet, {
					flag: row.original.flag,
					location: row.getValue('location') as string
				});
			},
			header: 'Location'
		},
		{
			accessorKey: 'status',
			cell: ({ row }) =>
				renderComponent(Badge, {
					children: createRawSnippet(() => {
						const status = row.getValue('status') as string;
						return {
							render: () => status
						};
					}),

					class: cn(
						row.getValue('status') === 'Inactive' &&
							'bg-muted-foreground/60 text-primary-foreground'
					)
				}),
			header: 'Status'
		},
		{
			accessorKey: 'balance',
			cell: ({ row }) => {
				return renderSnippet(
					createRawSnippet((getBalance) => {
						const balance = getBalance() as string;
						const formatted = new Intl.NumberFormat('en-US', {
							currency: 'USD',
							style: 'currency'
						}).format(parseFloat(balance));
						return {
							render: () => `<div class="text-right">${formatted}</div>`
						};
					}),
					row.getValue('balance')
				);
			},
			header: () => {
				const nameSnippet = createRawSnippet(() => {
					return {
						render: () => `<div class="text-right">Balance</div>`
					};
				});
				return renderSnippet(nameSnippet, {});
			}
		}
	];

	let rowSelection = $state<RowSelectionState>({});
	let expanded = $state<ExpandedState>({});
	let data = $state<User[]>([]);

	$effect(() => {
		fetchUsers()
			.then((response) => {
				data = response.slice(0, 5);
			})
			.catch((err) => {
				console.error(err);
			});
	});

	const table = createSvelteTable<User>({
		columns,
		get data() {
			return data;
		},
		getCoreRowModel: getCoreRowModel(),
		getExpandedRowModel: getExpandedRowModel(),
		getRowCanExpand: (row) => Boolean(row.original.note),
		onExpandedChange: (updater) => {
			if (typeof updater === 'function') {
				expanded = updater(expanded);
			} else {
				expanded = updater;
			}
		},
		onRowSelectionChange: (updater) => {
			if (typeof updater === 'function') {
				rowSelection = updater(rowSelection);
			} else {
				rowSelection = updater;
			}
		},
		state: {
			get expanded() {
				return expanded;
			},
			get rowSelection() {
				return rowSelection;
			}
		}
	});
</script>

<div>
	<Table>
		<TableHeader>
			{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
				<TableRow class="hover:bg-transparent">
					{#each headerGroup.headers as header (header.id)}
						<TableHead>
							{#if !header.isPlaceholder}
								<FlexRender
									content={header.column.columnDef.header}
									context={header.getContext()}
								/>
							{/if}
						</TableHead>
					{/each}
				</TableRow>
			{/each}
		</TableHeader>
		<TableBody>
			{#each table.getRowModel().rows as row (row.id)}
				<TableRow data-state={row.getIsSelected() && 'selected'}>
					{#each row.getVisibleCells() as cell (cell.id)}
						<TableCell
							class="whitespace-nowrap [&:has([aria-expanded])]:w-px [&:has([aria-expanded])]:py-0 [&:has([aria-expanded])]:pr-0"
						>
							<FlexRender content={cell.column.columnDef.cell} context={cell.getContext()} />
						</TableCell>
					{/each}
				</TableRow>
				{#if row.getIsExpanded()}
					<TableRow>
						<TableCell colspan={row.getVisibleCells().length}>
							<div class="flex items-start py-2 text-primary/80">
								<span class="me-3 mt-0.5 flex w-7 shrink-0 justify-center" aria-hidden="true">
									<Info class="opacity-60" size={16} />
								</span>
								<p class="text-sm">{row.original.note}</p>
							</div>
						</TableCell>
					</TableRow>
				{/if}
			{:else}
				<TableRow>
					<TableCell colspan={columns.length} class="h-24 text-center">No results.</TableCell>
				</TableRow>
			{/each}
		</TableBody>
	</Table>
	<p class="mt-4 text-center text-sm text-muted-foreground">
		Expanding sub-row made with
		<a
			class="underline hover:text-foreground"
			href="https://tanstack.com/table"
			target="_blank"
			rel="noopener noreferrer"
		>
			TanStack Table
		</a>
	</p>
</div>

```

### Links

- [View Source](https://github.com/max-got/originui-svelte/tree/main/src/lib/components/tables/table-17.svelte)


## table-18

> A type-safe, accessible table-18 component for building modern UIs. This component is part of the tables collection.

### Core Information

- **Component ID**: `table-18`
- **Location**: `/src/lib/components/tables/table-18.svelte`
- **Type**: UI Component

### Usage

```svelte
### Dependencies

Required packages and components:

- [`lucide-svelte`](https://github.com/lucide-icons/lucide)

Full component implementation:

```svelte
<script lang="ts">
	import type { User } from '$data/api/data/users.handlers';

	import Badge from '$lib/components/ui/badge.svelte';
	import Button from '$lib/components/ui/button.svelte';
	import Checkbox from '$lib/components/ui/checkbox.svelte';
	import Label from '$lib/components/ui/label.svelte';

	import {
		type ColumnDef,
		getCoreRowModel,
		getPaginationRowModel,
		getSortedRowModel,
		type PaginationState,
		type RowSelectionState,
		type SortingState
	} from '@tanstack/table-core';
	import { fetchUsers } from '$data/api/data/users';
	import {
		createSvelteTable,
		FlexRender,
		renderComponent,
		renderSnippet
	} from '$lib/components/ui/data-table';
	import { Pagination, PaginationContent, PaginationItem } from '$lib/components/ui/pagination';
	import { Select, SelectContent, SelectItem, SelectTrigger } from '$lib/components/ui/select';
	import {
		Table,
		TableBody,
		TableCell,
		TableHead,
		TableHeader,
		TableRow
	} from '$lib/components/ui/table';
	import { cn } from '$lib/utils';
	import ChevronDown from 'lucide-svelte/icons/chevron-down';
	import ChevronFirst from 'lucide-svelte/icons/chevron-first';
	import ChevronLast from 'lucide-svelte/icons/chevron-last';
	import ChevronLeft from 'lucide-svelte/icons/chevron-left';
	import ChevronRight from 'lucide-svelte/icons/chevron-right';
	import ChevronUp from 'lucide-svelte/icons/chevron-up';
	import { createRawSnippet } from 'svelte';

	const columns: ColumnDef<User>[] = [
		{
			cell: ({ row }) =>
				renderComponent(Checkbox, {
					'aria-label': 'Select row',
					checked: row.getIsSelected(),
					onCheckedChange: (value) => row.toggleSelected(!!value)
				}),
			enableSorting: false,
			header: ({ table }) =>
				renderComponent(Checkbox, {
					'aria-label': 'Select all',
					checked: table.getIsAllPageRowsSelected(),
					indeterminate: table.getIsSomePageRowsSelected() && !table.getIsAllPageRowsSelected(),
					onCheckedChange: (value) => table.toggleAllPageRowsSelected(!!value)
				}),
			id: 'select',
			size: 28
		},
		{
			accessorKey: 'name',
			cell: ({ row }) => {
				const nameSnippet = createRawSnippet<[string]>((getName) => {
					const name = getName();
					return {
						render: () => `<div class="font-medium">${name}</div>`
					};
				});
				return renderSnippet(nameSnippet, row.getValue('name'));
			},
			header: 'Name',
			size: 180
		},
		{
			accessorKey: 'email',
			header: 'Email',
			size: 200
		},
		{
			accessorKey: 'location',
			cell: ({ row }) => {
				const locationSnippet = createRawSnippet<[{ flag: string; location: string }]>((args) => {
					const { flag, location } = args();
					return {
						render: () => `
							<div>
								<span class="text-lg leading-none">${flag}</span>
								${location}
							</div>`
					};
				});
				return renderSnippet(locationSnippet, {
					flag: row.original.flag,
					location: row.getValue('location') as string
				});
			},
			header: 'Location',
			size: 180
		},
		{
			accessorKey: 'status',
			cell: ({ row }) =>
				renderComponent(Badge, {
					children: createRawSnippet(() => {
						const status = row.getValue('status') as string;
						return {
							render: () => status
						};
					}),

					class: cn(
						row.getValue('status') === 'Inactive' &&
							'bg-muted-foreground/60 text-primary-foreground'
					)
				}),
			header: 'Status',
			size: 120
		},
		{
			accessorKey: 'balance',
			cell: ({ row }) => {
				const amount = parseFloat(row.getValue('balance'));
				const formatted = new Intl.NumberFormat('en-US', {
					currency: 'USD',
					style: 'currency'
				}).format(amount);
				return formatted;
			},
			header: 'Balance',
			size: 120
		}
	];

	const id = $props.id();

	let pagination = $state<PaginationState>({
		pageIndex: 0,
		pageSize: 5
	});
	let sorting = $state<SortingState>([
		{
			desc: false,
			id: 'name'
		}
	]);
	let rowSelection = $state<RowSelectionState>({});
	let data = $state<User[]>([]);

	$effect(() => {
		fetchUsers()
			.then((response) => {
				data = [...response];
			})
			.catch((err) => {
				console.error(err);
			});
	});

	const table = createSvelteTable<User>({
		columns,
		get data() {
			return data;
		},
		enableSortingRemoval: false,
		getCoreRowModel: getCoreRowModel(),
		getPaginationRowModel: getPaginationRowModel(),
		getSortedRowModel: getSortedRowModel(),
		onPaginationChange: (updater) => {
			if (typeof updater === 'function') {
				pagination = updater(pagination);
			} else {
				pagination = updater;
			}
		},
		onRowSelectionChange: (updater) => {
			if (typeof updater === 'function') {
				rowSelection = updater(rowSelection);
			} else {
				rowSelection = updater;
			}
		},
		onSortingChange: (updater) => {
			if (typeof updater === 'function') {
				sorting = updater(sorting);
			} else {
				sorting = updater;
			}
		},
		state: {
			get pagination() {
				return pagination;
			},
			get rowSelection() {
				return rowSelection;
			},
			get sorting() {
				return sorting;
			}
		}
	});
</script>

<div class="space-y-4">
	<div class="overflow-hidden rounded-md border bg-background">
		<Table class="table-fixed">
			<TableHeader>
				{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
					<TableRow class="hover:bg-transparent">
						{#each headerGroup.headers as header (header.id)}
							<TableHead style="width: {header.getSize()}px" class="h-11">
								{#if !header.isPlaceholder && header.column.getCanSort()}
									<div
										class={cn(
											header.column.getCanSort() &&
												'flex h-full cursor-pointer select-none items-center justify-between gap-2'
										)}
										onclick={header.column.getToggleSortingHandler()}
										onkeydown={(e) => {
											// Enhanced keyboard handling for sorting
											if (header.column.getCanSort() && (e.key === 'Enter' || e.key === ' ')) {
												e.preventDefault();
												header.column.getToggleSortingHandler()?.(e);
											}
										}}
										tabIndex={header.column.getCanSort() ? 0 : undefined}
									>
										<FlexRender
											content={header.column.columnDef.header}
											context={header.getContext()}
										/>
										{#if header.column.getIsSorted() === 'asc'}
											<ChevronUp class="shrink-0 opacity-60" size={16} aria-hidden="true" />
										{:else if header.column.getIsSorted() === 'desc'}
											<ChevronDown class="shrink-0 opacity-60" size={16} aria-hidden="true" />
										{/if}
									</div>
								{:else if !header.isPlaceholder && !header.column.getCanSort()}
									<FlexRender
										content={header.column.columnDef.header}
										context={header.getContext()}
									/>
								{/if}
							</TableHead>
						{/each}
					</TableRow>
				{/each}
			</TableHeader>
			<TableBody>
				{#each table.getRowModel().rows as row (row.id)}
					<TableRow data-state={row.getIsSelected() && 'selected'}>
						{#each row.getVisibleCells() as cell (cell.id)}
							<TableCell>
								<FlexRender content={cell.column.columnDef.cell} context={cell.getContext()} />
							</TableCell>
						{/each}
					</TableRow>
				{:else}
					<TableRow>
						<TableCell colspan={columns.length} class="h-24 text-center">No results.</TableCell>
					</TableRow>
				{/each}
			</TableBody>
		</Table>
	</div>

	<!-- Pagination -->
	<div class="flex items-center justify-between gap-8">
		<!-- Results per page -->
		<div class="flex items-center gap-3">
			<Label for={id} class="max-sm:sr-only">Rows per page</Label>
			<Select
				type="single"
				value={table.getState().pagination.pageSize.toString()}
				onValueChange={(value) => {
					table.setPageSize(Number(value));
				}}
			>
				<SelectTrigger placeholder="Select number of results" {id} class="w-fit whitespace-nowrap">
					{table.getState().pagination.pageSize.toString()}
				</SelectTrigger>
				<SelectContent
					class="[&_*[role=option]>span]:end-2 [&_*[role=option]>span]:start-auto [&_*[role=option]]:pe-8 [&_*[role=option]]:ps-2"
				>
					{#each [5, 10, 25, 50] as pageSize (pageSize)}
						<SelectItem value={pageSize.toString()}>
							{pageSize}
						</SelectItem>
					{/each}
				</SelectContent>
			</Select>
		</div>
		<!-- Page number information -->
		<div class="flex grow justify-end whitespace-nowrap text-sm text-muted-foreground">
			<p class="whitespace-nowrap text-sm text-muted-foreground" aria-live="polite">
				<span class="text-foreground">
					{table.getState().pagination.pageIndex * table.getState().pagination.pageSize + 1}
					-
					{Math.min(
						Math.max(
							table.getState().pagination.pageIndex * table.getState().pagination.pageSize +
								table.getState().pagination.pageSize,
							0
						),
						table.getRowCount()
					)}
				</span>
				of
				<span class="text-foreground">
					{table.getRowCount().toString()}
				</span>
			</p>
		</div>
		<!-- Pagination buttons -->
		<div>
			<Pagination>
				<PaginationContent>
					<!-- First page button -->
					<PaginationItem>
						<Button
							size="icon"
							variant="outline"
							class="disabled:pointer-events-none disabled:opacity-50"
							onclick={() => table.firstPage()}
							disabled={!table.getCanPreviousPage()}
							aria-label="Go to first page"
						>
							<ChevronFirst size={16} aria-hidden="true" />
						</Button>
					</PaginationItem>
					<!-- Previous page button -->
					<PaginationItem>
						<Button
							size="icon"
							variant="outline"
							class="disabled:pointer-events-none disabled:opacity-50"
							onclick={() => table.previousPage()}
							disabled={!table.getCanPreviousPage()}
							aria-label="Go to previous page"
						>
							<ChevronLeft size={16} aria-hidden="true" />
						</Button>
					</PaginationItem>
					<!-- Next page button -->
					<PaginationItem>
						<Button
							size="icon"
							variant="outline"
							class="disabled:pointer-events-none disabled:opacity-50"
							onclick={() => table.nextPage()}
							disabled={!table.getCanNextPage()}
							aria-label="Go to next page"
						>
							<ChevronRight size={16} aria-hidden="true" />
						</Button>
					</PaginationItem>
					<!-- Last page button -->
					<PaginationItem>
						<Button
							size="icon"
							variant="outline"
							class="disabled:pointer-events-none disabled:opacity-50"
							onclick={() => table.lastPage()}
							disabled={!table.getCanNextPage()}
							aria-label="Go to last page"
						>
							<ChevronLast size={16} aria-hidden="true" />
						</Button>
					</PaginationItem>
				</PaginationContent>
			</Pagination>
		</div>
	</div>
	<p class="mt-4 text-center text-sm text-muted-foreground">
		Paginated table made with
		<a
			class="underline hover:text-foreground"
			href="https://tanstack.com/table"
			target="_blank"
			rel="noopener noreferrer"
		>
			TanStack Table
		</a>
	</p>
</div>

```

### Links

- [View Source](https://github.com/max-got/originui-svelte/tree/main/src/lib/components/tables/table-18.svelte)


## table-19

> A type-safe, accessible table-19 component for building modern UIs. This component is part of the tables collection.

### Core Information

- **Component ID**: `table-19`
- **Location**: `/src/lib/components/tables/table-19.svelte`
- **Type**: UI Component

### Usage

```svelte
### Dependencies

Required packages and components:

- [`lucide-svelte`](https://github.com/lucide-icons/lucide)

Full component implementation:

```svelte
<script lang="ts">
	import type { User } from '$data/api/data/users.handlers';

	import Badge from '$lib/components/ui/badge.svelte';
	import Button from '$lib/components/ui/button.svelte';
	import Checkbox from '$lib/components/ui/checkbox.svelte';
	import { usePagination } from '$lib/hooks/use-pagination.svelte';

	import {
		type ColumnDef,
		getCoreRowModel,
		getPaginationRowModel,
		getSortedRowModel,
		type PaginationState,
		type RowSelectionState,
		type SortingState
	} from '@tanstack/table-core';
	import { fetchUsers } from '$data/api/data/users';
	import {
		createSvelteTable,
		FlexRender,
		renderComponent,
		renderSnippet
	} from '$lib/components/ui/data-table';
	import {
		Pagination,
		PaginationContent,
		PaginationEllipsis,
		PaginationItem
	} from '$lib/components/ui/pagination';
	import {
		Select,
		SelectContent,
		SelectItem,
		SelectTrigger
		// SelectValue
	} from '$lib/components/ui/select';
	import {
		Table,
		TableBody,
		TableCell,
		TableHead,
		TableHeader,
		TableRow
	} from '$lib/components/ui/table';
	import { cn } from '$lib/utils';
	import ChevronDown from 'lucide-svelte/icons/chevron-down';
	import ChevronLeft from 'lucide-svelte/icons/chevron-left';
	import ChevronRight from 'lucide-svelte/icons/chevron-right';
	import ChevronUp from 'lucide-svelte/icons/chevron-up';
	import { createRawSnippet } from 'svelte';

	const columns: ColumnDef<User>[] = [
		{
			cell: ({ row }) =>
				renderComponent(Checkbox, {
					'aria-label': 'Select row',
					checked: row.getIsSelected(),
					onCheckedChange: (value) => row.toggleSelected(!!value)
				}),
			enableSorting: false,
			header: ({ table }) =>
				renderComponent(Checkbox, {
					'aria-label': 'Select all rows',
					checked: table.getIsAllPageRowsSelected(),
					indeterminate: table.getIsSomePageRowsSelected() && !table.getIsAllPageRowsSelected(),
					onCheckedChange: (value) => table.toggleAllPageRowsSelected(!!value)
				}),
			id: 'select',
			size: 28
		},
		{
			accessorKey: 'name',
			cell: ({ row }) => {
				const nameSnippet = createRawSnippet<[string]>((getName) => {
					const name = getName();
					return {
						render: () => `<div class="font-medium">${name}</div>`
					};
				});
				return renderSnippet(nameSnippet, row.getValue('name'));
			},
			header: 'Name',
			size: 180
		},
		{
			accessorKey: 'email',
			header: 'Email',
			size: 200
		},
		{
			accessorKey: 'location',
			cell: ({ row }) => {
				const locationSnippet = createRawSnippet<[{ flag: string; location: string }]>((args) => {
					const { flag, location } = args();
					return {
						render: () => `
							<div>
								<span class="text-lg leading-none">${flag}</span>
								${location}
							</div>`
					};
				});
				return renderSnippet(locationSnippet, {
					flag: row.original.flag,
					location: row.getValue('location') as string
				});
			},
			header: 'Location',
			size: 180
		},
		{
			accessorKey: 'status',
			cell: ({ row }) =>
				renderComponent(Badge, {
					children: createRawSnippet(() => {
						const status = row.getValue('status') as string;
						return {
							render: () => status
						};
					}),

					class: cn(
						row.getValue('status') === 'Inactive' &&
							'bg-muted-foreground/60 text-primary-foreground'
					)
				}),
			header: 'Status',
			size: 120
		},
		{
			accessorKey: 'balance',
			cell: ({ row }) => {
				const amount = parseFloat(row.getValue('balance'));
				const formatted = new Intl.NumberFormat('en-US', {
					currency: 'USD',
					style: 'currency'
				}).format(amount);
				return formatted;
			},
			header: 'Balance',
			size: 120
		}
	];

	let pageSize = $state(5);
	let pagination = $state<PaginationState>({
		pageIndex: 0,
		pageSize: pageSize
	});
	let sorting = $state<SortingState>([
		{
			desc: false,
			id: 'name'
		}
	]);
	let rowSelection = $state<RowSelectionState>({});
	let data = $state<User[]>([]);

	$effect(() => {
		fetchUsers()
			.then((response) => {
				data = [...response];
			})
			.catch((err) => {
				console.error(err);
			});
	});

	const table = createSvelteTable<User>({
		columns,
		get data() {
			return data;
		},
		enableSortingRemoval: false,
		getCoreRowModel: getCoreRowModel(),
		getPaginationRowModel: getPaginationRowModel(),
		getSortedRowModel: getSortedRowModel(),
		onPaginationChange: (updater) => {
			if (typeof updater === 'function') {
				pagination = updater(pagination);
			} else {
				pagination = updater;
			}
		},
		onRowSelectionChange: (updater) => {
			if (typeof updater === 'function') {
				rowSelection = updater(rowSelection);
			} else {
				rowSelection = updater;
			}
		},
		onSortingChange: (updater) => {
			if (typeof updater === 'function') {
				sorting = updater(sorting);
			} else {
				sorting = updater;
			}
		},
		state: {
			get pagination() {
				return pagination;
			},
			get rowSelection() {
				return rowSelection;
			},
			get sorting() {
				return sorting;
			}
		}
	});

	const paginated = $derived(
		usePagination({
			currentPage: table.getState().pagination.pageIndex + 1,
			paginationItemsToDisplay: 5,
			totalPages: table.getPageCount()
		})
	);
</script>

<div class="space-y-4">
	<div class="overflow-hidden rounded-md border bg-background">
		<Table class="table-fixed">
			<TableHeader>
				{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
					<TableRow class="hover:bg-transparent">
						{#each headerGroup.headers as header (header.id)}
							<TableHead style="width: {header.getSize()}px" class="h-11">
								{#if !header.isPlaceholder && header.column.getCanSort()}
									<div
										class={cn(
											header.column.getCanSort() &&
												'flex h-full cursor-pointer select-none items-center justify-between gap-2'
										)}
										onclick={header.column.getToggleSortingHandler()}
										onkeydown={(e) => {
											// Enhanced keyboard handling for sorting
											if (header.column.getCanSort() && (e.key === 'Enter' || e.key === ' ')) {
												e.preventDefault();
												header.column.getToggleSortingHandler()?.(e);
											}
										}}
										tabIndex={header.column.getCanSort() ? 0 : undefined}
									>
										<FlexRender
											content={header.column.columnDef.header}
											context={header.getContext()}
										/>
										{#if header.column.getIsSorted() === 'asc'}
											<ChevronUp class="shrink-0 opacity-60" size={16} aria-hidden="true" />
										{:else if header.column.getIsSorted() === 'desc'}
											<ChevronDown class="shrink-0 opacity-60" size={16} aria-hidden="true" />
										{/if}
									</div>
								{:else if !header.isPlaceholder && !header.column.getCanSort()}
									<FlexRender
										content={header.column.columnDef.header}
										context={header.getContext()}
									/>
								{/if}
							</TableHead>
						{/each}
					</TableRow>
				{/each}
			</TableHeader>
			<TableBody>
				{#each table.getRowModel().rows as row (row.id)}
					<TableRow data-state={row.getIsSelected() && 'selected'}>
						{#each row.getVisibleCells() as cell (cell.id)}
							<TableCell>
								<FlexRender content={cell.column.columnDef.cell} context={cell.getContext()} />
							</TableCell>
						{/each}
					</TableRow>
				{:else}
					<TableRow>
						<TableCell colspan={columns.length} class="h-24 text-center">No results.</TableCell>
					</TableRow>
				{/each}
			</TableBody>
		</Table>
	</div>

	<!-- Pagination -->
	<div class="flex items-center justify-between gap-3 max-sm:flex-col">
		<!-- Page number information -->
		<p class="flex-1 whitespace-nowrap text-sm text-muted-foreground" aria-live="polite">
			Page
			<span class="text-foreground">
				{table.getState().pagination.pageIndex + 1}
			</span>
			of <span class="text-foreground">{table.getPageCount()}</span>
		</p>

		<!-- Pagination buttons -->
		<div class="grow">
			<Pagination>
				<PaginationContent>
					<!-- Previous page button -->
					<PaginationItem>
						<Button
							size="icon"
							variant="outline"
							class="disabled:pointer-events-none disabled:opacity-50"
							onclick={() => table.previousPage()}
							disabled={!table.getCanPreviousPage()}
							aria-label="Go to previous page"
						>
							<ChevronLeft size={16} aria-hidden="true" />
						</Button>
					</PaginationItem>

					<!-- Left ellipsis (...) -->
					{#if paginated.showLeftEllipsis}
						<PaginationItem>
							<PaginationEllipsis />
						</PaginationItem>
					{/if}

					<!-- Page number buttons -->
					{#each paginated.pages as page (page)}
						{@const isActive = page === table.getState().pagination.pageIndex + 1}
						<PaginationItem>
							<Button
								size="icon"
								variant={`${isActive ? 'outline' : 'ghost'}`}
								onclick={() => table.setPageIndex(page - 1)}
								aria-current={isActive ? 'page' : undefined}
							>
								{page}
							</Button>
						</PaginationItem>
					{:else}
						<p>empty</p>
					{/each}

					<!-- Right ellipsis (...) -->
					{#if paginated.showRightEllipsis}
						<PaginationItem>
							<PaginationEllipsis />
						</PaginationItem>
					{/if}

					<!-- Next page button -->
					<PaginationItem>
						<Button
							size="icon"
							variant="outline"
							class="disabled:pointer-events-none disabled:opacity-50"
							onclick={() => table.nextPage()}
							disabled={!table.getCanNextPage()}
							aria-label="Go to next page"
						>
							<ChevronRight size={16} aria-hidden="true" />
						</Button>
					</PaginationItem>
				</PaginationContent>
			</Pagination>
		</div>

		<!-- Results per page -->
		<div class="flex flex-1 justify-end">
			<Select
				type="single"
				value={table.getState().pagination.pageSize.toString()}
				onValueChange={(value) => {
					table.setPageSize(Number(value));
				}}
			>
				<SelectTrigger
					id="results-per-page"
					class="w-fit whitespace-nowrap"
					placeholder="Select number of results"
					aria-label="Results per page"
				>
					{table.getState().pagination.pageSize.toString()} / page
				</SelectTrigger>
				<SelectContent>
					{#each [5, 10, 25, 50] as pageSize (pageSize)}
						<SelectItem value={pageSize.toString()}>
							{pageSize} / page
						</SelectItem>
					{/each}
				</SelectContent>
			</Select>
		</div>
	</div>
	<p class="mt-4 text-center text-sm text-muted-foreground">
		Numeric pagination made with
		<a
			class="underline hover:text-foreground"
			href="https://tanstack.com/table"
			target="_blank"
			rel="noopener noreferrer"
		>
			TanStack Table
		</a>
	</p>
</div>

```

### Links

- [View Source](https://github.com/max-got/originui-svelte/tree/main/src/lib/components/tables/table-19.svelte)


## table-20

> A type-safe, accessible table-20 component for building modern UIs. This component is part of the tables collection.

### Core Information

- **Component ID**: `table-20`
- **Location**: `/src/lib/components/tables/table-20.svelte`
- **Type**: UI Component

### Usage

```svelte
### Dependencies

Required packages and components:

- [`lucide-svelte`](https://github.com/lucide-icons/lucide)

Full component implementation:

```svelte
<script lang="ts">
	import type { User } from '$data/api/data/users.handlers';

	import Badge from '$lib/components/ui/badge.svelte';
	import Button from '$lib/components/ui/button.svelte';
	import Checkbox from '$lib/components/ui/checkbox.svelte';
	import Input from '$lib/components/ui/input.svelte';
	import Label from '$lib/components/ui/label.svelte';

	import {
		type ColumnDef,
		type ColumnFiltersState,
		type FilterFn,
		getCoreRowModel,
		getFacetedUniqueValues,
		getFilteredRowModel,
		getPaginationRowModel,
		getSortedRowModel,
		type PaginationState,
		type RowSelectionState,
		type SortingState,
		type VisibilityState
	} from '@tanstack/table-core';
	import {
		AlertDialogAction,
		AlertDialogCancel,
		AlertDialogContent,
		AlertDialogDescription,
		AlertDialogFooter,
		AlertDialogHeader,
		AlertDialogRoot,
		AlertDialogTitle,
		AlertDialogTrigger
	} from '$lib/components/ui/alert-dialog';
	import {
		createSvelteTable,
		FlexRender,
		renderComponent,
		renderSnippet
	} from '$lib/components/ui/data-table';
	import {
		DropdownMenu,
		DropdownMenuCheckboxItem,
		DropdownMenuContent,
		DropdownMenuGroup,
		DropdownMenuItem,
		DropdownMenuLabel,
		DropdownMenuSeparator,
		DropdownMenuShortcut,
		DropdownMenuSub,
		DropdownMenuSubContent,
		DropdownMenuSubTrigger,
		DropdownMenuTrigger
	} from '$lib/components/ui/dropdowns';
	import { Pagination, PaginationContent, PaginationItem } from '$lib/components/ui/pagination';
	import { Popover, PopoverContent, PopoverTrigger } from '$lib/components/ui/popover';
	import { Select, SelectContent, SelectItem, SelectTrigger } from '$lib/components/ui/select';
	import {
		Table,
		TableBody,
		TableCell,
		TableHead,
		TableHeader,
		TableRow
	} from '$lib/components/ui/table';
	import { cn } from '$lib/utils';
	import ChevronDown from 'lucide-svelte/icons/chevron-down';
	import ChevronFirst from 'lucide-svelte/icons/chevron-first';
	import ChevronLast from 'lucide-svelte/icons/chevron-last';
	import ChevronLeft from 'lucide-svelte/icons/chevron-left';
	import ChevronRight from 'lucide-svelte/icons/chevron-right';
	import ChevronUp from 'lucide-svelte/icons/chevron-up';
	import CircleAlert from 'lucide-svelte/icons/circle-alert';
	import CircleX from 'lucide-svelte/icons/circle-x';
	import Columns3 from 'lucide-svelte/icons/columns-3';
	import Ellipsis from 'lucide-svelte/icons/ellipsis';
	import Filter from 'lucide-svelte/icons/filter';
	import ListFilter from 'lucide-svelte/icons/list-filter';
	import Plus from 'lucide-svelte/icons/plus';
	import Trash from 'lucide-svelte/icons/trash';
	import { createRawSnippet } from 'svelte';

	// Custom filter function for multi-column searching
	const multiColumnFilterFn: FilterFn<User> = (row, _, filterValue) => {
		const searchableRowContent = `${row.original.name} ${row.original.email}`.toLowerCase();
		const searchTerm = (filterValue ?? '').toLowerCase();
		return searchableRowContent.includes(searchTerm);
	};

	const statusFilterFn: FilterFn<User> = (row, columnId, filterValue: string[]) => {
		if (!filterValue?.length) return true;
		const status = row.getValue(columnId) as string;
		return filterValue.includes(status);
	};

	const columns: ColumnDef<User>[] = [
		{
			cell: ({ row }) =>
				renderComponent(Checkbox, {
					'aria-label': 'Select row',
					checked: row.getIsSelected(),
					onCheckedChange: (value) => row.toggleSelected(!!value)
				}),
			enableHiding: false,
			enableSorting: false,
			header: ({ table }) =>
				renderComponent(Checkbox, {
					'aria-label': 'Select all',
					checked: table.getIsAllPageRowsSelected(),
					indeterminate: table.getIsSomePageRowsSelected() && !table.getIsAllPageRowsSelected(),
					onCheckedChange: (value) => table.toggleAllPageRowsSelected(!!value)
				}),
			id: 'select',
			size: 28
		},
		{
			accessorKey: 'name',
			cell: ({ row }) => {
				const nameSnippet = createRawSnippet<[string]>((getName) => {
					const name = getName();
					return {
						render: () => `<div class="font-medium">${name}</div>`
					};
				});
				return renderSnippet(nameSnippet, row.getValue('name'));
			},
			enableHiding: false,
			filterFn: multiColumnFilterFn,
			header: 'Name',
			size: 180
		},
		{
			accessorKey: 'email',
			header: 'Email',
			size: 220
		},
		{
			accessorKey: 'location',
			cell: ({ row }) => {
				const locationSnippet = createRawSnippet<[{ flag: string; location: string }]>((args) => {
					const { flag, location } = args();
					return {
						render: () => `
							<div>
								<span class="text-lg leading-none">${flag}</span>
								${location}
							</div>`
					};
				});
				return renderSnippet(locationSnippet, {
					flag: row.original.flag,
					location: row.getValue('location') as string
				});
			},
			header: 'Location',
			size: 180
		},
		{
			accessorKey: 'status',
			cell: ({ row }) =>
				renderComponent(Badge, {
					children: createRawSnippet(() => {
						const status = row.getValue('status') as string;
						return {
							render: () => status
						};
					}),
					class: cn(
						row.getValue('status') === 'Inactive' &&
							'bg-muted-foreground/60 text-primary-foreground'
					)
				}),
			filterFn: statusFilterFn,
			header: 'Status',
			size: 100
		},
		{
			accessorKey: 'performance',
			header: 'Performance'
		},
		{
			accessorKey: 'balance',
			cell: ({ row }) => {
				const amount = parseFloat(row.getValue('balance'));
				const formatted = new Intl.NumberFormat('en-US', {
					currency: 'USD',
					style: 'currency'
				}).format(amount);
				return formatted;
			},
			header: 'Balance',
			size: 120
		},
		{
			cell: ({ row }) => renderSnippet(RowActions, { row }),
			enableHiding: false,
			header: () =>
				renderSnippet(
					createRawSnippet(() => {
						return {
							render: () => `<span class="sr-only">Actions</span>`
						};
					}),
					{}
				),
			id: 'actions',
			size: 60
		}
	];

	let columnFilters = $state<ColumnFiltersState>([]);
	let columnVisibility = $state<VisibilityState>({});
	let pagination = $state<PaginationState>({
		pageIndex: 0,
		pageSize: 10
	});
	let rowSelection = $state<RowSelectionState>({});
	let sorting = $state<SortingState>([
		{
			desc: false,
			id: 'name'
		}
	]);
	let data = $state<User[]>([]);

	$effect(() => {
		fetch('https://res.cloudinary.com/dlzlfasou/raw/upload/users-01_fertyx.json')
			.then((res) => res.json())
			.then((response) => {
				data = response;
			})
			.catch((err) => {
				console.error(err);
			});
	});

	function handleDeleteRows() {
		const selectedRows = table.getSelectedRowModel().rows;
		data = data.filter((item) => !selectedRows.some((row) => row.original.id === item.id));
		table.resetRowSelection();
	}

	const table = createSvelteTable<User>({
		columns,
		get data() {
			return data;
		},
		enableSortingRemoval: false,
		getCoreRowModel: getCoreRowModel(),
		getFacetedUniqueValues: getFacetedUniqueValues(),
		getFilteredRowModel: getFilteredRowModel(),
		getPaginationRowModel: getPaginationRowModel(),
		getSortedRowModel: getSortedRowModel(),
		onColumnFiltersChange: (updater) => {
			if (typeof updater === 'function') {
				columnFilters = updater(columnFilters);
			} else {
				columnFilters = updater;
			}
		},
		onColumnVisibilityChange: (updater) => {
			if (typeof updater === 'function') {
				columnVisibility = updater(columnVisibility);
			} else {
				columnVisibility = updater;
			}
		},
		onPaginationChange: (updater) => {
			if (typeof updater === 'function') {
				pagination = updater(pagination);
			} else {
				pagination = updater;
			}
		},
		onRowSelectionChange: (updater) => {
			if (typeof updater === 'function') {
				rowSelection = updater(rowSelection);
			} else {
				rowSelection = updater;
			}
		},
		onSortingChange: (updater) => {
			if (typeof updater === 'function') {
				sorting = updater(sorting);
			} else {
				sorting = updater;
			}
		},
		state: {
			get columnFilters() {
				return columnFilters;
			},
			get columnVisibility() {
				return columnVisibility;
			},
			get pagination() {
				return pagination;
			},
			get rowSelection() {
				return rowSelection;
			},
			get sorting() {
				return sorting;
			}
		}
	});

	const uniqueStatusValues = $derived.by(() => {
		const statusColumn = table.getColumn('status');
		if (!statusColumn) return [];
		return Array.from(statusColumn.getFacetedUniqueValues().keys()).sort();
	});

	const statusCounts = $derived.by(() => {
		const statusColumn = table.getColumn('status');
		if (!statusColumn) return new Map();
		return statusColumn.getFacetedUniqueValues();
	});

	const selectedStatuses = $derived.by(() => {
		const filterValue = table.getColumn('status')?.getFilterValue() as string[];
		return filterValue ?? [];
	});

	function handleStatusChange(checked: boolean, value: string) {
		const filterValue = table.getColumn('status')?.getFilterValue() as string[];
		const newFilterValue = filterValue ? [...filterValue] : [];

		if (checked) {
			newFilterValue.push(value);
		} else {
			const index = newFilterValue.indexOf(value);
			if (index > -1) {
				newFilterValue.splice(index, 1);
			}
		}

		table.getColumn('status')?.setFilterValue(newFilterValue.length ? newFilterValue : undefined);
	}
</script>

<div class="space-y-4">
	<!-- Filters -->
	<div class="flex flex-wrap items-center justify-between gap-3">
		<div class="flex items-center gap-3">
			<!-- Filter by name or email -->
			<div class="relative">
				<Input
					class={cn(
						'peer min-w-60 ps-9',
						Boolean(table.getColumn('name')?.getFilterValue()) && 'pe-9'
					)}
					value={(table.getColumn('name')?.getFilterValue() ?? '') as string}
					oninput={(e) => table.getColumn('name')?.setFilterValue(e.currentTarget.value)}
					placeholder="Filter by name or email..."
					type="text"
					aria-label="Filter by name or email"
				/>
				<div
					class="pointer-events-none absolute inset-y-0 start-0 flex items-center justify-center ps-3 text-muted-foreground/80 peer-disabled:opacity-50"
				>
					<ListFilter size={16} aria-hidden="true" />
				</div>
				{#if Boolean(table.getColumn('name')?.getFilterValue())}
					<button
						class="absolute inset-y-0 end-0 flex h-full w-9 items-center justify-center rounded-e-md text-muted-foreground/80 outline-none transition-[color,box-shadow] hover:text-foreground focus:z-10 focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50"
						aria-label="Clear filter"
						onclick={() => {
							table.getColumn('name')?.setFilterValue('');
						}}
					>
						<CircleX size={16} aria-hidden="true" />
					</button>
				{/if}
			</div>
			<!-- Filter by status -->
			<Popover>
				<PopoverTrigger>
					{#snippet child({ props })}
						<Button variant="outline" {...props}>
							<Filter class="-ms-1 opacity-60" size={16} aria-hidden="true" />
							Status
							{#if selectedStatuses.length > 0}
								<span
									class="-me-1 inline-flex h-5 max-h-full items-center rounded border bg-background px-1 font-[inherit] text-[0.625rem] font-medium text-muted-foreground/70"
								>
									{selectedStatuses.length}
								</span>
							{/if}
						</Button>
					{/snippet}
				</PopoverTrigger>
				<PopoverContent class="w-auto min-w-36 p-3" align="start">
					<div class="space-y-3">
						<div class="text-xs font-medium text-muted-foreground">Filters</div>
						<div class="space-y-3">
							{#each uniqueStatusValues as value (value)}
								<div class="flex items-center gap-2">
									<Checkbox
										checked={selectedStatuses.includes(value)}
										onCheckedChange={(checked: boolean) => handleStatusChange(checked, value)}
									/>
									<Label class="flex grow justify-between gap-2 font-normal">
										{value}
										<span class="ms-2 text-xs text-muted-foreground">
											{statusCounts.get(value)}
										</span>
									</Label>
								</div>
							{/each}
						</div>
					</div>
				</PopoverContent>
			</Popover>
			<!-- Toggle columns visibility -->
			<DropdownMenu>
				<DropdownMenuTrigger>
					{#snippet child({ props })}
						<Button variant="outline" {...props}>
							<Columns3 class="-ms-1 opacity-60" size={16} aria-hidden="true" />
							View
						</Button>
					{/snippet}
				</DropdownMenuTrigger>
				<DropdownMenuContent align="end">
					<DropdownMenuLabel>Toggle columns</DropdownMenuLabel>
					{#each table
						.getAllColumns()
						.filter((column) => column.getCanHide()) as column (column.id)}
						<DropdownMenuCheckboxItem
							class="capitalize"
							checked={column.getIsVisible()}
							onCheckedChange={(value) => column.toggleVisibility(!!value)}
						>
							{column.id}
						</DropdownMenuCheckboxItem>
					{/each}
				</DropdownMenuContent>
			</DropdownMenu>
		</div>
		<div class="flex items-center gap-3">
			<!-- Delete button -->
			{#if table.getSelectedRowModel().rows.length > 0}
				<AlertDialogRoot>
					<AlertDialogTrigger>
						{#snippet child({ props })}
							<Button class="ml-auto" variant="outline" {...props}>
								<Trash class="-ms-1 opacity-60" size={16} aria-hidden="true" />
								Delete
								<span
									class="-me-1 inline-flex h-5 max-h-full items-center rounded border bg-background px-1 font-[inherit] text-[0.625rem] font-medium text-muted-foreground/70"
								>
									{table.getSelectedRowModel().rows.length}
								</span>
							</Button>
						{/snippet}
					</AlertDialogTrigger>
					<AlertDialogContent>
						<div class="flex flex-col gap-2 max-sm:items-center sm:flex-row sm:gap-4">
							<div
								class="flex size-9 shrink-0 items-center justify-center rounded-full border"
								aria-hidden="true"
							>
								<CircleAlert class="opacity-80" size={16} />
							</div>
							<AlertDialogHeader>
								<AlertDialogTitle>Are you absolutely sure?</AlertDialogTitle>
								<AlertDialogDescription>
									This action cannot be undone. This will permanently delete
									{table.getSelectedRowModel().rows.length} selected
									{table.getSelectedRowModel().rows.length === 1 ? 'row' : 'rows'}.
								</AlertDialogDescription>
							</AlertDialogHeader>
						</div>
						<AlertDialogFooter>
							<AlertDialogCancel>Cancel</AlertDialogCancel>
							<AlertDialogAction onclick={handleDeleteRows}>Delete</AlertDialogAction>
						</AlertDialogFooter>
					</AlertDialogContent>
				</AlertDialogRoot>
			{/if}
			<!-- Add user button -->
			<Button class="ml-auto" variant="outline">
				<Plus class="-ms-1 opacity-60" size={16} aria-hidden="true" />
				Add user
			</Button>
		</div>
	</div>

	<!-- Table -->
	<div class="overflow-hidden rounded-md border bg-background">
		<Table class="table-fixed">
			<TableHeader>
				{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
					<TableRow class="hover:bg-transparent">
						{#each headerGroup.headers as header (header.id)}
							<TableHead style="width: {header.getSize()}px" class="h-11">
								{#if !header.isPlaceholder && header.column.getCanSort()}
									<div
										class={cn(
											header.column.getCanSort() &&
												'flex h-full cursor-pointer select-none items-center justify-between gap-2'
										)}
										onclick={header.column.getToggleSortingHandler()}
										onkeydown={(e) => {
											if (header.column.getCanSort() && (e.key === 'Enter' || e.key === ' ')) {
												e.preventDefault();
												header.column.getToggleSortingHandler()?.(e);
											}
										}}
										tabindex={header.column.getCanSort() ? 0 : undefined}
									>
										<FlexRender
											content={header.column.columnDef.header}
											context={header.getContext()}
										/>
										{#if header.column.getIsSorted() === 'asc'}
											<ChevronUp class="shrink-0 opacity-60" size={16} aria-hidden="true" />
										{:else if header.column.getIsSorted() === 'desc'}
											<ChevronDown class="shrink-0 opacity-60" size={16} aria-hidden="true" />
										{/if}
									</div>
								{:else if !header.isPlaceholder && !header.column.getCanSort()}
									<FlexRender
										content={header.column.columnDef.header}
										context={header.getContext()}
									/>
								{/if}
							</TableHead>
						{/each}
					</TableRow>
				{/each}
			</TableHeader>
			<TableBody>
				{#if table.getRowModel().rows?.length}
					{#each table.getRowModel().rows as row (row.id)}
						<TableRow data-state={row.getIsSelected() && 'selected'}>
							{#each row.getVisibleCells() as cell (cell.id)}
								<TableCell class="last:py-0">
									<FlexRender content={cell.column.columnDef.cell} context={cell.getContext()} />
								</TableCell>
							{/each}
						</TableRow>
					{:else}
						<TableRow>
							<TableCell colspan={columns.length} class="h-24 text-center">No results.</TableCell>
						</TableRow>
					{/each}
				{/if}
			</TableBody>
		</Table>
	</div>

	<!-- Pagination -->
	<div class="flex items-center justify-between gap-8">
		<!-- Results per page -->
		<div class="flex items-center gap-3">
			<Label class="max-sm:sr-only">Rows per page</Label>
			<Select
				type="single"
				value={table.getState().pagination.pageSize.toString()}
				onValueChange={(value) => {
					table.setPageSize(Number(value));
				}}
			>
				<SelectTrigger class="w-fit whitespace-nowrap">
					{table.getState().pagination.pageSize.toString() ?? 'Select number of results'}
				</SelectTrigger>
				<SelectContent
					class="[&_*[role=option]>span]:end-2 [&_*[role=option]>span]:start-auto [&_*[role=option]]:pe-8 [&_*[role=option]]:ps-2"
				>
					{#each [5, 10, 25, 50] as pageSize (pageSize)}
						<SelectItem value={pageSize.toString()}>
							{pageSize}
						</SelectItem>
					{/each}
				</SelectContent>
			</Select>
		</div>
		<!-- Page number information -->
		<div class="flex grow justify-end whitespace-nowrap text-sm text-muted-foreground">
			<p class="whitespace-nowrap text-sm text-muted-foreground" aria-live="polite">
				<span class="text-foreground">
					{table.getState().pagination.pageIndex * table.getState().pagination.pageSize +
						1}-{Math.min(
						Math.max(
							table.getState().pagination.pageIndex * table.getState().pagination.pageSize +
								table.getState().pagination.pageSize,
							0
						),
						table.getRowCount()
					)}
				</span>
				of
				<span class="text-foreground">
					{table.getRowCount().toString()}
				</span>
			</p>
		</div>

		<!-- Pagination buttons -->
		<div>
			<Pagination>
				<PaginationContent>
					<!-- First page button -->
					<PaginationItem>
						<Button
							size="icon"
							variant="outline"
							class="disabled:pointer-events-none disabled:opacity-50"
							onclick={() => table.firstPage()}
							disabled={!table.getCanPreviousPage()}
							aria-label="Go to first page"
						>
							<ChevronFirst size={16} aria-hidden="true" />
						</Button>
					</PaginationItem>
					<!-- Previous page button -->
					<PaginationItem>
						<Button
							size="icon"
							variant="outline"
							class="disabled:pointer-events-none disabled:opacity-50"
							onclick={() => table.previousPage()}
							disabled={!table.getCanPreviousPage()}
							aria-label="Go to previous page"
						>
							<ChevronLeft size={16} aria-hidden="true" />
						</Button>
					</PaginationItem>
					<!-- Next page button -->
					<PaginationItem>
						<Button
							size="icon"
							variant="outline"
							class="disabled:pointer-events-none disabled:opacity-50"
							onclick={() => table.nextPage()}
							disabled={!table.getCanNextPage()}
							aria-label="Go to next page"
						>
							<ChevronRight size={16} aria-hidden="true" />
						</Button>
					</PaginationItem>
					<!-- Last page button -->
					<PaginationItem>
						<Button
							size="icon"
							variant="outline"
							class="disabled:pointer-events-none disabled:opacity-50"
							onclick={() => table.lastPage()}
							disabled={!table.getCanNextPage()}
							aria-label="Go to last page"
						>
							<ChevronLast size={16} aria-hidden="true" />
						</Button>
					</PaginationItem>
				</PaginationContent>
			</Pagination>
		</div>
	</div>
	<p class="mt-4 text-center text-sm text-muted-foreground">
		Example of a more complex table made with
		<a
			class="underline hover:text-foreground"
			href="https://tanstack.com/table"
			target="_blank"
			rel="noopener noreferrer"
		>
			TanStack Table
		</a>
	</p>
</div>

{#snippet RowActions()}
	<DropdownMenu>
		<DropdownMenuTrigger>
			{#snippet child({ props })}
				<div class="flex justify-end">
					<Button size="icon" variant="ghost" class="shadow-none" aria-label="Edit item" {...props}>
						<Ellipsis size={16} aria-hidden="true" />
					</Button>
				</div>
			{/snippet}
		</DropdownMenuTrigger>
		<DropdownMenuContent align="end">
			<DropdownMenuGroup>
				<DropdownMenuItem>
					<span>Edit</span>
					<DropdownMenuShortcut>⌘E</DropdownMenuShortcut>
				</DropdownMenuItem>
				<DropdownMenuItem>
					<span>Duplicate</span>
					<DropdownMenuShortcut>⌘D</DropdownMenuShortcut>
				</DropdownMenuItem>
			</DropdownMenuGroup>
			<DropdownMenuSeparator />
			<DropdownMenuGroup>
				<DropdownMenuItem>
					<span>Archive</span>
					<DropdownMenuShortcut>⌘A</DropdownMenuShortcut>
				</DropdownMenuItem>
				<DropdownMenuSub>
					<DropdownMenuSubTrigger>More</DropdownMenuSubTrigger>

					<DropdownMenuSubContent>
						<DropdownMenuItem>Move to project</DropdownMenuItem>
						<DropdownMenuItem>Move to folder</DropdownMenuItem>
						<DropdownMenuSeparator />
						<DropdownMenuItem>Advanced options</DropdownMenuItem>
					</DropdownMenuSubContent>
				</DropdownMenuSub>
			</DropdownMenuGroup>
			<DropdownMenuSeparator />
			<DropdownMenuGroup>
				<DropdownMenuItem>
					<span>Share</span>
					<DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
				</DropdownMenuItem>
				<DropdownMenuItem>
					<span>Add to favorites</span>
					<DropdownMenuShortcut>⌘F</DropdownMenuShortcut>
				</DropdownMenuItem>
			</DropdownMenuGroup>
			<DropdownMenuSeparator />
			<DropdownMenuItem class="text-destructive focus:text-destructive">
				<span>Delete</span>
				<DropdownMenuShortcut>⌘⌫</DropdownMenuShortcut>
			</DropdownMenuItem>
		</DropdownMenuContent>
	</DropdownMenu>
{/snippet}

```

### Links

- [View Source](https://github.com/max-got/originui-svelte/tree/main/src/lib/components/tables/table-20.svelte)