UI Component Test Page
A showcase of all UI components, variants, colors, and typography
Font Family
Headings Font
Space Grotesk
The quick brown fox
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789
Body Font
Geist Sans
The quick brown fox jumps over the lazy dog
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789
Typography
Heading 1
The quick brown fox
Heading 2
The quick brown fox
Heading 3
The quick brown fox
Heading 4
The quick brown fox
Body Large
The quick brown fox jumps over the lazy dog
Body (Base)
The quick brown fox jumps over the lazy dog
Body Small
The quick brown fox jumps over the lazy dog
Caption
The quick brown fox jumps over the lazy dog
Color Palette
bg-background
bg-foreground
bg-primary
bg-secondary
bg-muted
bg-accent
bg-destructive
bg-card
Button Component
Variants
variant="default"
variant="secondary"
variant="link"
Sizes
size="sm"
size="default"
size="lg"
size="icon"
States
default state
disabled
isLoading
Variant + Size Combinations
Default Variant
Secondary Variant
Link Variant
Navigation Menu Component
Simple navigation menu with links
Breadcrumb Component
Navigation breadcrumbs showing the current page location within the site hierarchy
Basic Breadcrumb
Simple two-level breadcrumb navigation
Three-Level Breadcrumb
Breadcrumb with three levels of navigation
Four-Level Breadcrumb
Deep navigation with four levels
Collapsed Breadcrumb
Long breadcrumbs can use ellipsis to collapse middle items
Real-World Examples
Firm Detail Page
Billing Page
Invites Page
Key Features
Dark Mode Support
Uses semantic tokens (text-muted-foreground, hover:text-foreground) that automatically adapt to light and dark themes
Accessible Navigation
Proper semantic HTML with nav and ordered list elements
Responsive
Adapts to mobile screens with flexible wrapping
Clear Hierarchy
Visual separators and current page highlighting for clarity
Usage Example
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
import Link from "next/link";
// Basic breadcrumb
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink asChild>
<Link href="/firms">Firms</Link>
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Acme Financial</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
// Three-level breadcrumb
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink asChild>
<Link href="/firms">Firms</Link>
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink asChild>
<Link href="/firms/123">Acme Financial</Link>
</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>Billing</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>Borders & Spacing
Border Colors
Border Radius
Skeleton Component
Loading state placeholders for data fetching
Basic Shapes
Text Line (Full Width)
Text Line (3/4 Width)
Text Line (1/2 Width)
Circle (Avatar)
Square / Rectangle
Card Skeleton
Common pattern for loading card content
Profile Skeleton
Avatar with text pattern
List/Table Skeleton
Multiple rows for table/list loading
Dashboard Skeleton
Complex layout with multiple sections
Toast Notifications
Simple toast notifications for user feedback using Sonner
Basic Toasts
Toast with Description
Toast with Action
Custom Duration
Promise Toast
Automatically handles loading, success, and error states
Usage Example
import { toast } from "sonner";
// Basic
toast("Message");
// With type
toast.success("Success!");
toast.error("Error!");
toast.info("Info");
toast.warning("Warning");
// With description
toast.success("Title", {
description: "Description text",
});
// With action
toast("Event created", {
action: {
label: "View",
onClick: () => console.log("View"),
},
});
// Promise
toast.promise(promise, {
loading: "Loading...",
success: "Done!",
error: "Failed",
});Table Component
Data tables with automatic dark mode support using semantic tokens
Basic Table
Simple table showing firm data with semantic colors
| Name | Type | Status | Created Date |
|---|---|---|---|
| Acme Financial | HOME_OFFICE | Active | Jan 15, 2024 |
| Wealth Advisors Co | DEFAULT | Active | Feb 3, 2024 |
| Investment Partners LLC | DEFAULT | Pending | Mar 12, 2024 |
| Global Finance Group | HOME_OFFICE | Inactive | Apr 8, 2024 |
| Premier Wealth | DEFAULT | Error | May 20, 2024 |
Key Features
Dark Mode Support
Uses semantic tokens (bg-card, text-muted-foreground, border) that automatically adapt to light and dark themes
Hover States
Rows support hover:bg-muted/50 for interactive feedback
Status Badges
Badge colors include dark mode variants for proper contrast
Accessible
Proper semantic HTML with thead, tbody, th, and td elements
Fixed Width & Text Truncation (REQUIRED)
MANDATORY pattern: All tables MUST use fixed column widths with text truncation to prevent column jumping during pagination
| Company Name | Email Address | Status |
|---|---|---|
Very Long Company Name That Will Be Truncated With Ellipsis | verylongemail@companyname.com | Active |
Short Name | user@example.com | Pending |
Another Extremely Long Business Name That Demonstrates Truncation | anotherlongemailaddress@business.co | Inactive |
⚠️ REQUIRED PATTERN
- Add
width="XXXpx"prop to all TableHead components - Add
truncateclass to ALL content divs inside cells - Add
titleattribute to show full text on hover - Prevents column width changes during pagination
- Ensures single-line row height (no text wrapping)
Usage Example with Fixed Widths
import { createColumnHelper } from "@tanstack/react-table";
const columnHelper = createColumnHelper<DataType>();
// ✅ Define columns with fixed widths in meta
const columns = [
columnHelper.accessor("name", {
header: "Name",
cell: (info) => (
// ✅ REQUIRED: truncate + title
<div className="font-medium truncate" title={info.getValue() || ""}>
{info.getValue() || "—"}
</div>
),
meta: { width: "200px" }, // ✅ Fixed width
}),
columnHelper.accessor("email", {
header: "Email",
cell: (info) => (
<div className="text-sm truncate" title={info.getValue() || ""}>
{info.getValue() || "—"}
</div>
),
meta: { width: "250px" },
}),
];
// ✅ Pass width from meta to TableHead
<TableHeader>
{table.getHeaderGroups().map((headerGroup) => (
<TableRow key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<TableHead
key={header.id}
width={(header.column.columnDef.meta as ColumnMeta)?.width}
>
{flexRender(header.column.columnDef.header, header.getContext())}
</TableHead>
))}
</TableRow>
))}
</TableHeader>Switch Component
A toggle switch for boolean settings and feature flags
Basic States
defaultChecked={true}
Default state
disabled
disabled defaultChecked
Controlled Example
Interactive example with state management
Current state: ✗ Disabled
Common Use Cases
Feature Flags
Display advisor information on generated reports
Receive email updates about changes
Usage Example
import { Switch } from "@/components/ui/switch";
import { Label } from "@/components/ui/label";
import { useState } from "react";
// Basic usage with label
<div className="flex items-center space-x-2">
<Switch id="airplane-mode" />
<Label htmlFor="airplane-mode">Airplane Mode</Label>
</div>
// Controlled with state
const [enabled, setEnabled] = useState(false);
<Switch
id="notifications"
checked={enabled}
onCheckedChange={setEnabled}
/>
// Disabled
<Switch id="feature" disabled />
// With description
<div className="flex items-center justify-between">
<div>
<Label htmlFor="feature">Feature Name</Label>
<p className="text-sm text-muted-foreground">
Description of the feature
</p>
</div>
<Switch id="feature" />
</div>AlertDialog Component
A modal dialog for important decisions requiring user confirmation
Basic Confirmation
Simple confirmation dialog with cancel and confirm actions
Controlled Dialog
Programmatically control dialog open/close state
Dialog is currently: Closed
Common Use Cases
Feature Toggle
Confirm before enabling/disabling a feature
Data Loss Warning
Warn users before destructive actions
Usage Example
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { Button } from "@/components/ui/button";
// Basic usage
<AlertDialog>
<AlertDialogTrigger asChild>
<Button>Delete Account</Button>
</AlertDialogTrigger>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Are you sure?</AlertDialogTitle>
<AlertDialogDescription>
This action cannot be undone.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction onClick={handleDelete}>
Delete
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
// Controlled usage
const [open, setOpen] = useState(false);
<AlertDialog open={open} onOpenChange={setOpen}>
<AlertDialogContent>
{/* ... */}
</AlertDialogContent>
</AlertDialog>
// Trigger programmatically
<Button onClick={() => setOpen(true)}>
Open Dialog
</Button>Drawer Component
A sliding panel for displaying content from the edge of the screen
Basic Drawer
Drawer with trigger button (slides from bottom by default)
Right Side Drawer
Ideal for edit forms and detail panels
Controlled Drawer
Programmatically control drawer open/close state
Drawer is currently: Closed
Usage Example
import {
Drawer,
DrawerClose,
DrawerContent,
DrawerDescription,
DrawerFooter,
DrawerHeader,
DrawerTitle,
DrawerTrigger,
} from "@/components/ui/drawer";
// With trigger (uncontrolled)
<Drawer>
<DrawerTrigger asChild>
<Button>Open</Button>
</DrawerTrigger>
<DrawerContent>
<DrawerHeader>
<DrawerTitle>Title</DrawerTitle>
</DrawerHeader>
<div className="p-4">Content</div>
<DrawerFooter>
<DrawerClose asChild>
<Button>Close</Button>
</DrawerClose>
</DrawerFooter>
</DrawerContent>
</Drawer>
// Controlled with state
const [open, setOpen] = useState(false);
<Drawer open={open} onOpenChange={setOpen} direction="right">
<DrawerContent>
{/* ... */}
</DrawerContent>
</Drawer>Form Component with Validation
Form components with React Hook Form and Zod validation
Form with Validation
Demonstrates field validation, error messages, and submission
Drawer with Form
Complete edit flow: Drawer + Form + Validation
Usage Example
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import {
Form,
FormField,
FormItem,
FormLabel,
FormControl,
FormMessage,
} from "@/components/ui/form";
// 1. Define schema
const formSchema = z.object({
email: z.string().email("Invalid email"),
age: z.number().min(18, "Must be 18+"),
});
type FormValues = z.infer<typeof formSchema>;
// 2. Component
function MyForm() {
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: { email: "", age: 0 },
});
const onSubmit = (data: FormValues) => {
console.log(data);
};
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<Button type="submit">Submit</Button>
</form>
</Form>
);
}