Skip to content

Commit 385239f

Browse files
committed
docs: add base ui shadcn examples
1 parent b12a65b commit 385239f

55 files changed

Lines changed: 7287 additions & 1 deletion

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/config.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1136,7 +1136,9 @@
11361136
"label": "react",
11371137
"children": [
11381138
{ "to": "framework/react/examples/lib-shadcn-radix", "label": "Basic - Shadcn (Radix)" },
1139-
{ "to": "framework/react/examples/kitchen-sink-shadcn-radix", "label": "Kitchen Sink - Shadcn (Radix)" }
1139+
{ "to": "framework/react/examples/lib-shadcn-base", "label": "Basic - Shadcn (Base UI)" },
1140+
{ "to": "framework/react/examples/kitchen-sink-shadcn-radix", "label": "Kitchen Sink - Shadcn (Radix)" },
1141+
{ "to": "framework/react/examples/kitchen-sink-shadcn-base", "label": "Kitchen Sink - Shadcn (Base UI)" }
11401142
]
11411143
}
11421144
]
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
node_modules
2+
.DS_Store
3+
dist
4+
dist-ssr
5+
*.local
6+
!lib
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Example
2+
3+
To run this example:
4+
5+
- `npm install` or `yarn`
6+
- `npm run start` or `yarn start`
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"$schema": "https://ui.shadcn.com/schema.json",
3+
"style": "new-york",
4+
"rsc": false,
5+
"tsx": true,
6+
"tailwind": {
7+
"config": "",
8+
"css": "src/styles/globals.css",
9+
"baseColor": "zinc",
10+
"cssVariables": true,
11+
"prefix": ""
12+
},
13+
"aliases": {
14+
"components": "@/components",
15+
"utils": "@/lib/utils",
16+
"ui": "@/components/ui",
17+
"lib": "@/lib",
18+
"hooks": "@/hooks"
19+
},
20+
"iconLibrary": "lucide"
21+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Vite App</title>
7+
<script src="https://unpkg.com/react-scan/dist/auto.global.js"></script>
8+
</head>
9+
<body>
10+
<div id="root"></div>
11+
<script type="module" src="/src/main.tsx"></script>
12+
</body>
13+
</html>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{
2+
"name": "tanstack-react-table-example-kitchen-sink-shadcn-base",
3+
"private": true,
4+
"scripts": {
5+
"dev": "vite",
6+
"build": "vite build",
7+
"serve": "vite preview",
8+
"start": "vite",
9+
"lint": "eslint ./src",
10+
"test:types": "tsc",
11+
"shadcn": "pnpm dlx shadcn@latest"
12+
},
13+
"dependencies": {
14+
"@base-ui/react": "^1.4.1",
15+
"@dnd-kit/core": "^6.3.1",
16+
"@dnd-kit/modifiers": "^9.0.0",
17+
"@dnd-kit/sortable": "^10.0.0",
18+
"@dnd-kit/utilities": "^3.2.2",
19+
"@faker-js/faker": "^10.4.0",
20+
"@tailwindcss/vite": "^4.2.4",
21+
"@tanstack/match-sorter-utils": "workspace:^",
22+
"@tanstack/react-table": "^9.0.0-alpha.40",
23+
"class-variance-authority": "^0.7.1",
24+
"clsx": "^2.1.1",
25+
"cmdk": "1.1.1",
26+
"date-fns": "^4.1.0",
27+
"lucide-react": "^1.11.0",
28+
"react": "^19.2.5",
29+
"react-day-picker": "9.14.0",
30+
"react-dom": "^19.2.5",
31+
"tailwind-merge": "^3.5.0",
32+
"tw-animate-css": "^1.4.0"
33+
},
34+
"devDependencies": {
35+
"@rolldown/plugin-babel": "^0.2.3",
36+
"@rollup/plugin-replace": "^6.0.3",
37+
"@types/react": "^19.2.14",
38+
"@types/react-dom": "^19.2.3",
39+
"@vitejs/plugin-react": "^6.0.1",
40+
"babel-plugin-react-compiler": "^1.0.0",
41+
"tailwindcss": "^4.2.4",
42+
"typescript": "6.0.3",
43+
"vite": "^8.0.10"
44+
}
45+
}
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
'use client'
2+
3+
import {
4+
ArrowDown,
5+
ArrowUp,
6+
ChevronsUpDown,
7+
EyeOff,
8+
Group,
9+
Pin,
10+
PinOff,
11+
Ungroup,
12+
} from 'lucide-react'
13+
import type { Column, RowData, TableFeatures } from '@tanstack/react-table'
14+
15+
import { Button } from '@/components/ui/button'
16+
import {
17+
DropdownMenu,
18+
DropdownMenuContent,
19+
DropdownMenuItem,
20+
DropdownMenuSeparator,
21+
DropdownMenuTrigger,
22+
} from '@/components/ui/dropdown-menu'
23+
import { cn } from '@/lib/utils'
24+
25+
/**
26+
* Per-column header dropdown that consolidates the v9 column actions:
27+
* sort asc/desc, group by, pin left/right, unpin, and hide. Items are
28+
* conditionally rendered based on `column.getCan*()` so it's safe to use
29+
* even when some features are not registered.
30+
*
31+
* Inspired by the shadcn data-table docs `DataTableColumnHeader` component
32+
* (https://ui.shadcn.com/docs/components/radix/data-table) but extended to
33+
* cover grouping and pinning since the kitchen-sink uses the full v9 surface.
34+
*/
35+
/**
36+
* Features the dropdown queries on the column. Mirrors the generic shape the
37+
* other `data-table-*` components use (TFeatures extends TableFeatures,
38+
* narrowed via Pick at the use site).
39+
*/
40+
type ColumnHeaderFeatureKeys =
41+
| 'columnGroupingFeature'
42+
| 'columnPinningFeature'
43+
| 'columnVisibilityFeature'
44+
| 'rowSortingFeature'
45+
46+
interface DataTableColumnHeaderProps<
47+
TFeatures extends TableFeatures,
48+
TData extends RowData,
49+
> extends React.HTMLAttributes<HTMLDivElement> {
50+
column: Column<Pick<TFeatures, ColumnHeaderFeatureKeys>, TData>
51+
title: string
52+
}
53+
54+
export function DataTableColumnHeader<
55+
TFeatures extends TableFeatures,
56+
TData extends RowData,
57+
>({ column, title, className }: DataTableColumnHeaderProps<TFeatures, TData>) {
58+
const canSort = column.getCanSort()
59+
const canHide = column.getCanHide()
60+
const canPin = column.getCanPin()
61+
const canGroup = column.getCanGroup()
62+
63+
// No actions available — render the title plain.
64+
if (!canSort && !canHide && !canPin && !canGroup) {
65+
return <div className={cn(className)}>{title}</div>
66+
}
67+
68+
const sorted = canSort ? column.getIsSorted() : false
69+
const pinned = canPin ? column.getIsPinned() : false
70+
const grouped = canGroup ? column.getIsGrouped() : false
71+
72+
return (
73+
<div className={cn('flex items-center gap-2', className)}>
74+
<DropdownMenu>
75+
<DropdownMenuTrigger
76+
render={
77+
<Button
78+
variant="ghost"
79+
size="sm"
80+
className="-ml-3 h-8 data-[state=open]:bg-accent"
81+
/>
82+
}
83+
>
84+
<span>{title}</span>
85+
{sorted === 'desc' ? (
86+
<ArrowDown className="ml-2 size-4" />
87+
) : sorted === 'asc' ? (
88+
<ArrowUp className="ml-2 size-4" />
89+
) : canSort ? (
90+
<ChevronsUpDown className="ml-2 size-4" />
91+
) : null}
92+
</DropdownMenuTrigger>
93+
<DropdownMenuContent align="start">
94+
{canSort && (
95+
<>
96+
<DropdownMenuItem onClick={() => column.toggleSorting(false)}>
97+
<ArrowUp className="mr-2 size-3.5 text-muted-foreground/70" />
98+
Asc
99+
</DropdownMenuItem>
100+
<DropdownMenuItem onClick={() => column.toggleSorting(true)}>
101+
<ArrowDown className="mr-2 size-3.5 text-muted-foreground/70" />
102+
Desc
103+
</DropdownMenuItem>
104+
</>
105+
)}
106+
{canGroup && (
107+
<>
108+
{canSort ? <DropdownMenuSeparator /> : null}
109+
<DropdownMenuItem onClick={column.getToggleGroupingHandler()}>
110+
{grouped ? (
111+
<>
112+
<Ungroup className="mr-2 size-3.5 text-muted-foreground/70" />
113+
Ungroup
114+
</>
115+
) : (
116+
<>
117+
<Group className="mr-2 size-3.5 text-muted-foreground/70" />
118+
Group by
119+
</>
120+
)}
121+
</DropdownMenuItem>
122+
</>
123+
)}
124+
{canPin && (
125+
<>
126+
{canSort || canGroup ? <DropdownMenuSeparator /> : null}
127+
<DropdownMenuItem
128+
onClick={() => column.pin('left')}
129+
disabled={pinned === 'left'}
130+
>
131+
<Pin className="mr-2 size-3.5 text-muted-foreground/70" />
132+
Pin left
133+
</DropdownMenuItem>
134+
<DropdownMenuItem
135+
onClick={() => column.pin('right')}
136+
disabled={pinned === 'right'}
137+
>
138+
<Pin className="mr-2 size-3.5 rotate-180 text-muted-foreground/70" />
139+
Pin right
140+
</DropdownMenuItem>
141+
{pinned ? (
142+
<DropdownMenuItem onClick={() => column.pin(false)}>
143+
<PinOff className="mr-2 size-3.5 text-muted-foreground/70" />
144+
Unpin
145+
</DropdownMenuItem>
146+
) : null}
147+
</>
148+
)}
149+
{canHide && (
150+
<>
151+
<DropdownMenuSeparator />
152+
<DropdownMenuItem onClick={() => column.toggleVisibility(false)}>
153+
<EyeOff className="mr-2 size-3.5 text-muted-foreground/70" />
154+
Hide
155+
</DropdownMenuItem>
156+
</>
157+
)}
158+
</DropdownMenuContent>
159+
</DropdownMenu>
160+
</div>
161+
)
162+
}

0 commit comments

Comments
 (0)