Building with @jonmatum/next-shell
This skill gives you everything needed to build a Next.js application using @jonmatum/next-shell. Use it when:
- Scaffolding a new app from scratch
- Adding pages, layouts, or features to an existing next-shell app
- Composing primitives into custom components
- Wiring up authentication, theming, or navigation
- Using hooks, formatters, or the command bar
Quick setup (new app)
npx degit jonmatum/next-shell/templates/starter my-app
cd my-app && pnpm install && pnpm dev
Or manually:
pnpm add @jonmatum/next-shell next@^15 react@^19 react-dom@^19 tailwindcss@^4
pnpm add -D @tailwindcss/postcss@^4
postcss.config.mjs (required)
export default { plugins: { '@tailwindcss/postcss': {} } };
globals.css (required)
@import 'tailwindcss';
@source "node_modules/@jonmatum/next-shell/dist/**/*.{js,cjs}";
@import '@jonmatum/next-shell/styles/preset.css';
Both tailwindcss AND @tailwindcss/postcss are required dependencies. Without them, @import 'tailwindcss' in globals.css will fail with "Can't resolve 'tailwindcss'".
The @source line is mandatory — Tailwind v4 skips node_modules by default.
Subpath imports (complete map)
| Import |
What it provides |
@jonmatum/next-shell/primitives |
42 shadcn/ui primitives: Button, Card, Dialog, Sheet, DropdownMenu, Table, Tabs, Form, Input, Select, Checkbox, Switch, etc. |
@jonmatum/next-shell/layout |
AppShell, Sidebar, SidebarNav, TopBar, CommandBar, CommandBarTrigger, CommandBarProvider, useCommandBar, useCommandBarActions, Breadcrumbs, ContentContainer, PageHeader, Footer, buildNav, EmptyState, ErrorState, LoadingState, ErrorPage, NotFound, etc. |
@jonmatum/next-shell/layout/server |
getSidebarStateFromCookies, buildSidebarStateCookieHeader (server-safe) |
@jonmatum/next-shell/providers |
AppProviders, ThemeProvider, ThemeToggle, ThemeToggleDropdown, useTheme, QueryProvider, ToastProvider, ErrorBoundary, I18nProvider |
@jonmatum/next-shell/providers/server |
getThemeFromCookies, buildThemeCookieHeader (server-safe) |
@jonmatum/next-shell/auth |
AuthProvider, useSession, useUser, useHasPermission, useRequireAuth, SignedIn, SignedOut, RoleGate |
@jonmatum/next-shell/auth/nextauth |
createNextAuthAdapter (Auth.js v5) |
@jonmatum/next-shell/auth/mock |
createMockAuthAdapter (testing/prototyping) |
@jonmatum/next-shell/auth/server |
requireSession (Route Handler protection) |
@jonmatum/next-shell/hooks |
useDisclosure, useLocalStorage, useSessionStorage, useCopyToClipboard, useHotkey, useBreakpoint, useMediaQuery, useIsMobile, useMounted, useDebouncedValue, useDebouncedCallback, useControllableState, useIsomorphicLayoutEffect, useLocale |
@jonmatum/next-shell/formatters |
formatDate, formatRelativeTime, formatNumber, formatCurrency, formatPercent, formatCompact, formatFileSize, truncate, pluralize, toTitleCase, toKebabCase, slugify |
@jonmatum/next-shell/tokens |
colorTokens, radiusTokens, tokenSchemaVersion, BrandOverrides, hexToOklch, preset palettes (neutralPreset, greenPreset, orangePreset, redPreset, violetPreset) |
@jonmatum/next-shell/styles/preset.css |
Tailwind v4 preset (tokens + tw-animate-css + @theme mappings) |
@jonmatum/next-shell/styles/presets/{green,neutral,orange,red,violet}.css |
Color palette presets |
Hard rules
No raw colors. Every color must use semantic tokens: bg-background, text-foreground, border-border, text-primary, bg-destructive, text-muted-foreground, etc. Never use bg-white, text-gray-500, #hex, rgb(), or oklch() in component code.
'use client' is explicit. Any file using hooks, event handlers, or browser APIs needs 'use client' at the top. Server Components are the default in Next.js App Router.
Import from subpaths, not the root. Use @jonmatum/next-shell/primitives not @jonmatum/next-shell. Tree-shaking depends on subpath imports.
Server-safe imports for RSC. In Server Components, import from /layout/server, /providers/server, or /auth/server — never from the client-boundary barrels.
App shell pattern
// app/(shell)/layout.tsx
'use client';
import { usePathname } from 'next/navigation';
import {
AppShell, TopBar, Footer, Sidebar, SidebarContent, SidebarHeader,
SidebarFooter, SidebarNav, SidebarSeparator, SidebarTrigger,
Breadcrumbs, CommandBarActions, buildNav,
} from '@jonmatum/next-shell/layout';
import type { NavConfig } from '@jonmatum/next-shell/layout';
const NAV: NavConfig = [
{ id: 'dashboard', label: 'Dashboard', href: '/dashboard', icon: <HomeIcon /> },
{ id: 'settings', label: 'Settings', href: '/settings', icon: <SettingsIcon />,
children: [
{ id: 'profile', label: 'Profile', href: '/settings/profile' },
{ id: 'billing', label: 'Billing', href: '/settings/billing', requires: 'billing' },
],
},
{ id: 'admin', label: 'Admin', href: '/admin', icon: <ShieldIcon />, requires: 'admin' },
];
export default function ShellLayout({ children }: { children: React.ReactNode }) {
const pathname = usePathname();
const permissions = ['billing']; // from your auth system
const { items, breadcrumbs } = buildNav({ config: NAV, pathname, permissions });
return (
<AppShell
commandBar
sidebar={
<Sidebar>
<SidebarHeader>
<span className="text-lg font-bold">My App</span>
</SidebarHeader>
<SidebarContent>
<SidebarNav items={items} />
</SidebarContent>
<SidebarFooter>
<span className="text-sm text-muted-foreground">v1.0</span>
</SidebarFooter>
</Sidebar>
}
topBar={
<TopBar
left={<><SidebarTrigger /><Breadcrumbs config={NAV} pathname={pathname} permissions={permissions} /></>}
right={<ThemeToggleDropdown />}
/>
}
footer={<Footer>Built with next-shell</Footer>}
>
<CommandBarActions config={NAV} pathname={pathname} permissions={permissions} />
{children}
</AppShell>
);
}
Page pattern
// app/(shell)/dashboard/page.tsx
'use client';
import { PageHeader, ContentContainer } from '@jonmatum/next-shell/layout';
import { Card, CardContent, CardHeader, CardTitle, Button } from '@jonmatum/next-shell/primitives';
import { formatCurrency, formatRelativeTime } from '@jonmatum/next-shell/formatters';
export default function DashboardPage() {
return (
<>
<PageHeader
title="Dashboard"
description="Overview of your account"
actions={<Button>New project</Button>}
/>
<ContentContainer size="lg" className="py-6 space-y-6">
<div className="grid gap-4 md:grid-cols-3">
<Card>
<CardHeader><CardTitle>Revenue</CardTitle></CardHeader>
<CardContent>
<p className="text-2xl font-bold">{formatCurrency(48295, { currency: 'USD' })}</p>
</CardContent>
</Card>
</div>
</ContentContainer>
</>
);
}
Auth pattern
// app/providers.tsx
'use client';
import { AppProviders } from '@jonmatum/next-shell/providers';
import { AuthProvider } from '@jonmatum/next-shell/auth';
import { createMockAuthAdapter } from '@jonmatum/next-shell/auth/mock';
const mockAuth = createMockAuthAdapter({
user: { id: '1', name: 'Demo User', email: 'demo@example.com', roles: ['admin'] },
});
export function Providers({ children }: { children: React.ReactNode }) {
return (
<AppProviders themeProps={{ defaultTheme: 'system', enableSystem: true }}>
<AuthProvider adapter={mockAuth}>
{children}
</AuthProvider>
</AppProviders>
);
}
Auth guards in pages
import { SignedIn, SignedOut, RoleGate, useUser } from '@jonmatum/next-shell/auth';
function AdminPage() {
const user = useUser();
return (
<>
<SignedOut><p>Please sign in</p></SignedOut>
<SignedIn>
<p>Welcome, {user?.name}</p>
<RoleGate role="admin" fallback={<p>Admin access required</p>}>
<AdminPanel />
</RoleGate>
</SignedIn>
</>
);
}
Hooks cheat sheet
import {
useDisclosure, // { isOpen, open, close, toggle, onOpenChange }
useLocalStorage, // [value, setValue] — persists across sessions
useCopyToClipboard, // { copy, isCopied }
useHotkey, // useHotkey('k', callback, { meta: true })
useBreakpoint, // { current, isMobile, isDesktop }
useDebouncedValue, // debounced version of a value
} from '@jonmatum/next-shell/hooks';
Error pages
// app/not-found.tsx (Server Component — import from /layout/server)
import { NotFound } from '@jonmatum/next-shell/layout/server';
export default function NotFoundPage() { return <NotFound />; }
// app/error.tsx (Client Component)
'use client';
import { ErrorPage } from '@jonmatum/next-shell/layout';
export default function ErrorBoundary({ error, reset }: { error: Error; reset: () => void }) {
return <ErrorPage status="500" title="Something went wrong" description={error.message}
actions={<Button again</Button>} />;
}
Theming
Brand overrides (JS)
import type { BrandOverrides } from '@jonmatum/next-shell/tokens';
const brand: BrandOverrides = {
light: { primary: 'oklch(0.6 0.2 145)', 'primary-foreground': 'oklch(1 0 0)' },
dark: { primary: 'oklch(0.75 0.15 145)' },
radius: '0.75rem',
};
<ThemeProvider brand={brand}>{children}</ThemeProvider>
Preset palettes (CSS)
@import '@jonmatum/next-shell/styles/preset.css';
@import '@jonmatum/next-shell/styles/presets/green.css';
Available: green.css, neutral.css, orange.css, red.css, violet.css
Generate from hex
npx next-shell-theme --color '#10b981' --format both
Semantic token reference
Colors (all have Tailwind utilities)
Surface pairs: background/foreground, card/card-foreground, popover/popover-foreground, muted/muted-foreground, accent/accent-foreground, primary/primary-foreground, secondary/secondary-foreground, destructive/destructive-foreground, success/success-foreground, warning/warning-foreground, info/info-foreground
Standalone: border, input, ring, overlay
Sidebar: sidebar-background, sidebar-foreground, sidebar-primary, sidebar-primary-foreground, sidebar-accent, sidebar-accent-foreground, sidebar-border, sidebar-ring
Charts: chart-1 through chart-5
Other tokens
- Radius:
rounded-sm, rounded-md, rounded-lg, rounded-xl (all derived from --radius)
- Motion:
duration-fast (150ms), duration-normal (250ms), duration-slow (400ms)
- Easing:
ease-standard, ease-emphasized, ease-decelerate, ease-accelerate
- Shadows:
shadow-xs, shadow-sm, shadow-md, shadow-lg, shadow-xl, shadow-2xl
Composition recipes
DatePicker
import { Button, Calendar, Popover, PopoverContent, PopoverTrigger } from '@jonmatum/next-shell/primitives';
import { cn } from '@jonmatum/next-shell/core';
DataTable
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@jonmatum/next-shell/primitives';
// + @tanstack/react-table for sorting/filtering/pagination
Combobox
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList,
Popover, PopoverContent, PopoverTrigger } from '@jonmatum/next-shell/primitives';
Common patterns
Toast notifications
import { toast } from 'sonner'; // direct import, not from next-shell
toast.success('Saved!');
toast.error('Failed', { description: 'Try again' });
toast.promise(saveData(), { loading: 'Saving...', success: 'Done!', error: 'Failed' });
Form with validation
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage,
Input, Button } from '@jonmatum/next-shell/primitives';
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
Dialog with useDisclosure
import { useDisclosure } from '@jonmatum/next-shell/hooks';
import { Dialog, DialogContent, DialogTitle, Button } from '@jonmatum/next-shell/primitives';
function MyDialog() {
const { isOpen, open, onOpenChange } = useDisclosure();
return (
<>
<Button
<Dialog open={isOpen}
<DialogContent><DialogTitle>Title</DialogTitle></DialogContent>
</Dialog>
</>
);
}
Source: jonmatum/next-shell — distributed by TomeVault.
1---2name: next-shell-builder3description: Build production-grade Next.js applications using @jonmatum/next-shell. Use this skill when scaffolding new apps, adding pages, wiring up auth, composing layouts, or building features with the library's primitives, hooks, and formatters. Provides the complete API surface, import paths, composition patterns, and token system rules needed for rapid prototyping and production builds. Use when this capability is needed.4---56# Building with @jonmatum/next-shell78This skill gives you everything needed to build a Next.js application using `@jonmatum/next-shell`. Use it when:910- Scaffolding a new app from scratch11- Adding pages, layouts, or features to an existing next-shell app12- Composing primitives into custom components13- Wiring up authentication, theming, or navigation14- Using hooks, formatters, or the command bar1516## Quick setup (new app)1718```bash19npx degit jonmatum/next-shell/templates/starter my-app20cd my-app && pnpm install && pnpm dev21```2223Or manually:2425```bash26pnpm add @jonmatum/next-shell next@^15 react@^19 react-dom@^19 tailwindcss@^427pnpm add -D @tailwindcss/postcss@^428```2930### postcss.config.mjs (required)3132```js33export default { plugins: { '@tailwindcss/postcss': {} } };34```3536### globals.css (required)3738```css39@import 'tailwindcss';40@source "node_modules/@jonmatum/next-shell/dist/**/*.{js,cjs}";41@import '@jonmatum/next-shell/styles/preset.css';42```4344Both `tailwindcss` AND `@tailwindcss/postcss` are required dependencies. Without them, `@import 'tailwindcss'` in globals.css will fail with "Can't resolve 'tailwindcss'".4546The `@source` line is mandatory — Tailwind v4 skips node_modules by default.4748## Subpath imports (complete map)4950| Import | What it provides |51|--------|-----------------|52| `@jonmatum/next-shell/primitives` | 42 shadcn/ui primitives: Button, Card, Dialog, Sheet, DropdownMenu, Table, Tabs, Form, Input, Select, Checkbox, Switch, etc. |53| `@jonmatum/next-shell/layout` | AppShell, Sidebar, SidebarNav, TopBar, CommandBar, CommandBarTrigger, CommandBarProvider, useCommandBar, useCommandBarActions, Breadcrumbs, ContentContainer, PageHeader, Footer, buildNav, EmptyState, ErrorState, LoadingState, ErrorPage, NotFound, etc. |54| `@jonmatum/next-shell/layout/server` | getSidebarStateFromCookies, buildSidebarStateCookieHeader (server-safe) |55| `@jonmatum/next-shell/providers` | AppProviders, ThemeProvider, ThemeToggle, ThemeToggleDropdown, useTheme, QueryProvider, ToastProvider, ErrorBoundary, I18nProvider |56| `@jonmatum/next-shell/providers/server` | getThemeFromCookies, buildThemeCookieHeader (server-safe) |57| `@jonmatum/next-shell/auth` | AuthProvider, useSession, useUser, useHasPermission, useRequireAuth, SignedIn, SignedOut, RoleGate |58| `@jonmatum/next-shell/auth/nextauth` | createNextAuthAdapter (Auth.js v5) |59| `@jonmatum/next-shell/auth/mock` | createMockAuthAdapter (testing/prototyping) |60| `@jonmatum/next-shell/auth/server` | requireSession (Route Handler protection) |61| `@jonmatum/next-shell/hooks` | useDisclosure, useLocalStorage, useSessionStorage, useCopyToClipboard, useHotkey, useBreakpoint, useMediaQuery, useIsMobile, useMounted, useDebouncedValue, useDebouncedCallback, useControllableState, useIsomorphicLayoutEffect, useLocale |62| `@jonmatum/next-shell/formatters` | formatDate, formatRelativeTime, formatNumber, formatCurrency, formatPercent, formatCompact, formatFileSize, truncate, pluralize, toTitleCase, toKebabCase, slugify |63| `@jonmatum/next-shell/tokens` | colorTokens, radiusTokens, tokenSchemaVersion, BrandOverrides, hexToOklch, preset palettes (neutralPreset, greenPreset, orangePreset, redPreset, violetPreset) |64| `@jonmatum/next-shell/styles/preset.css` | Tailwind v4 preset (tokens + tw-animate-css + @theme mappings) |65| `@jonmatum/next-shell/styles/presets/{green,neutral,orange,red,violet}.css` | Color palette presets |6667## Hard rules68691. **No raw colors.** Every color must use semantic tokens: `bg-background`, `text-foreground`, `border-border`, `text-primary`, `bg-destructive`, `text-muted-foreground`, etc. Never use `bg-white`, `text-gray-500`, `#hex`, `rgb()`, or `oklch()` in component code.70712. **'use client' is explicit.** Any file using hooks, event handlers, or browser APIs needs `'use client'` at the top. Server Components are the default in Next.js App Router.72733. **Import from subpaths, not the root.** Use `@jonmatum/next-shell/primitives` not `@jonmatum/next-shell`. Tree-shaking depends on subpath imports.74754. **Server-safe imports for RSC.** In Server Components, import from `/layout/server`, `/providers/server`, or `/auth/server` — never from the client-boundary barrels.7677## App shell pattern7879```tsx80// app/(shell)/layout.tsx81'use client';8283import { usePathname } from 'next/navigation';84import {85 AppShell, TopBar, Footer, Sidebar, SidebarContent, SidebarHeader,86 SidebarFooter, SidebarNav, SidebarSeparator, SidebarTrigger,87 Breadcrumbs, CommandBarActions, buildNav,88} from '@jonmatum/next-shell/layout';89import type { NavConfig } from '@jonmatum/next-shell/layout';9091const NAV: NavConfig = [92 { id: 'dashboard', label: 'Dashboard', href: '/dashboard', icon: <HomeIcon /> },93 { id: 'settings', label: 'Settings', href: '/settings', icon: <SettingsIcon />,94 children: [95 { id: 'profile', label: 'Profile', href: '/settings/profile' },96 { id: 'billing', label: 'Billing', href: '/settings/billing', requires: 'billing' },97 ],98 },99 { id: 'admin', label: 'Admin', href: '/admin', icon: <ShieldIcon />, requires: 'admin' },100];101102export default function ShellLayout({ children }: { children: React.ReactNode }) {103 const pathname = usePathname();104 const permissions = ['billing']; // from your auth system105 const { items, breadcrumbs } = buildNav({ config: NAV, pathname, permissions });106107 return (108 <AppShell109 commandBar110 sidebar={111 <Sidebar>112 <SidebarHeader>113 <span className="text-lg font-bold">My App</span>114 </SidebarHeader>115 <SidebarContent>116 <SidebarNav items={items} />117 </SidebarContent>118 <SidebarFooter>119 <span className="text-sm text-muted-foreground">v1.0</span>120 </SidebarFooter>121 </Sidebar>122 }123 topBar={124 <TopBar125 left={<><SidebarTrigger /><Breadcrumbs config={NAV} pathname={pathname} permissions={permissions} /></>}126 right={<ThemeToggleDropdown />}127 />128 }129 footer={<Footer>Built with next-shell</Footer>}130 >131 <CommandBarActions config={NAV} pathname={pathname} permissions={permissions} />132 {children}133 </AppShell>134 );135}136```137138## Page pattern139140```tsx141// app/(shell)/dashboard/page.tsx142'use client';143144import { PageHeader, ContentContainer } from '@jonmatum/next-shell/layout';145import { Card, CardContent, CardHeader, CardTitle, Button } from '@jonmatum/next-shell/primitives';146import { formatCurrency, formatRelativeTime } from '@jonmatum/next-shell/formatters';147148export default function DashboardPage() {149 return (150 <>151 <PageHeader152 title="Dashboard"153 description="Overview of your account"154 actions={<Button>New project</Button>}155 />156 <ContentContainer size="lg" className="py-6 space-y-6">157 <div className="grid gap-4 md:grid-cols-3">158 <Card>159 <CardHeader><CardTitle>Revenue</CardTitle></CardHeader>160 <CardContent>161 <p className="text-2xl font-bold">{formatCurrency(48295, { currency: 'USD' })}</p>162 </CardContent>163 </Card>164 </div>165 </ContentContainer>166 </>167 );168}169```170171## Auth pattern172173```tsx174// app/providers.tsx175'use client';176177import { AppProviders } from '@jonmatum/next-shell/providers';178import { AuthProvider } from '@jonmatum/next-shell/auth';179import { createMockAuthAdapter } from '@jonmatum/next-shell/auth/mock';180181const mockAuth = createMockAuthAdapter({182 user: { id: '1', name: 'Demo User', email: 'demo@example.com', roles: ['admin'] },183});184185export function Providers({ children }: { children: React.ReactNode }) {186 return (187 <AppProviders themeProps={{ defaultTheme: 'system', enableSystem: true }}>188 <AuthProvider adapter={mockAuth}>189 {children}190 </AuthProvider>191 </AppProviders>192 );193}194```195196### Auth guards in pages197198```tsx199import { SignedIn, SignedOut, RoleGate, useUser } from '@jonmatum/next-shell/auth';200201function AdminPage() {202 const user = useUser();203 return (204 <>205 <SignedOut><p>Please sign in</p></SignedOut>206 <SignedIn>207 <p>Welcome, {user?.name}</p>208 <RoleGate role="admin" fallback={<p>Admin access required</p>}>209 <AdminPanel />210 </RoleGate>211 </SignedIn>212 </>213 );214}215```216217## Hooks cheat sheet218219```tsx220import {221 useDisclosure, // { isOpen, open, close, toggle, onOpenChange }222 useLocalStorage, // [value, setValue] — persists across sessions223 useCopyToClipboard, // { copy, isCopied }224 useHotkey, // useHotkey('k', callback, { meta: true })225 useBreakpoint, // { current, isMobile, isDesktop }226 useDebouncedValue, // debounced version of a value227} from '@jonmatum/next-shell/hooks';228```229230## Error pages231232```tsx233// app/not-found.tsx (Server Component — import from /layout/server)234import { NotFound } from '@jonmatum/next-shell/layout/server';235export default function NotFoundPage() { return <NotFound />; }236237// app/error.tsx (Client Component)238'use client';239import { ErrorPage } from '@jonmatum/next-shell/layout';240export default function ErrorBoundary({ error, reset }: { error: Error; reset: () => void }) {241 return <ErrorPage status="500" title="Something went wrong" description={error.message}242 actions={<Button onClick={reset}>Try again</Button>} />;243}244```245246## Theming247248### Brand overrides (JS)249250```tsx251import type { BrandOverrides } from '@jonmatum/next-shell/tokens';252253const brand: BrandOverrides = {254 light: { primary: 'oklch(0.6 0.2 145)', 'primary-foreground': 'oklch(1 0 0)' },255 dark: { primary: 'oklch(0.75 0.15 145)' },256 radius: '0.75rem',257};258259<ThemeProvider brand={brand}>{children}</ThemeProvider>260```261262### Preset palettes (CSS)263264```css265@import '@jonmatum/next-shell/styles/preset.css';266@import '@jonmatum/next-shell/styles/presets/green.css';267```268269Available: `green.css`, `neutral.css`, `orange.css`, `red.css`, `violet.css`270271### Generate from hex272273```bash274npx next-shell-theme --color '#10b981' --format both275```276277## Semantic token reference278279### Colors (all have Tailwind utilities)280281Surface pairs: `background/foreground`, `card/card-foreground`, `popover/popover-foreground`, `muted/muted-foreground`, `accent/accent-foreground`, `primary/primary-foreground`, `secondary/secondary-foreground`, `destructive/destructive-foreground`, `success/success-foreground`, `warning/warning-foreground`, `info/info-foreground`282283Standalone: `border`, `input`, `ring`, `overlay`284285Sidebar: `sidebar-background`, `sidebar-foreground`, `sidebar-primary`, `sidebar-primary-foreground`, `sidebar-accent`, `sidebar-accent-foreground`, `sidebar-border`, `sidebar-ring`286287Charts: `chart-1` through `chart-5`288289### Other tokens290291- Radius: `rounded-sm`, `rounded-md`, `rounded-lg`, `rounded-xl` (all derived from `--radius`)292- Motion: `duration-fast` (150ms), `duration-normal` (250ms), `duration-slow` (400ms)293- Easing: `ease-standard`, `ease-emphasized`, `ease-decelerate`, `ease-accelerate`294- Shadows: `shadow-xs`, `shadow-sm`, `shadow-md`, `shadow-lg`, `shadow-xl`, `shadow-2xl`295296## Composition recipes297298### DatePicker299300```tsx301import { Button, Calendar, Popover, PopoverContent, PopoverTrigger } from '@jonmatum/next-shell/primitives';302import { cn } from '@jonmatum/next-shell/core';303```304305### DataTable306307```tsx308import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@jonmatum/next-shell/primitives';309// + @tanstack/react-table for sorting/filtering/pagination310```311312### Combobox313314```tsx315import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList,316 Popover, PopoverContent, PopoverTrigger } from '@jonmatum/next-shell/primitives';317```318319## Common patterns320321### Toast notifications322323```tsx324import { toast } from 'sonner'; // direct import, not from next-shell325326toast.success('Saved!');327toast.error('Failed', { description: 'Try again' });328toast.promise(saveData(), { loading: 'Saving...', success: 'Done!', error: 'Failed' });329```330331### Form with validation332333```tsx334import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage,335 Input, Button } from '@jonmatum/next-shell/primitives';336import { useForm } from 'react-hook-form';337import { zodResolver } from '@hookform/resolvers/zod';338```339340### Dialog with useDisclosure341342```tsx343import { useDisclosure } from '@jonmatum/next-shell/hooks';344import { Dialog, DialogContent, DialogTitle, Button } from '@jonmatum/next-shell/primitives';345346function MyDialog() {347 const { isOpen, open, onOpenChange } = useDisclosure();348 return (349 <>350 <Button onClick={open}>Open</Button>351 <Dialog open={isOpen} onOpenChange={onOpenChange}>352 <DialogContent><DialogTitle>Title</DialogTitle></DialogContent>353 </Dialog>354 </>355 );356}357```358359---360> Source: [jonmatum/next-shell](https://github.com/jonmatum/next-shell) — distributed by [TomeVault](https://tomevault.io).361<!-- tomevault:4.0:skill_md:2026-06-15 -->