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

Background

bg-background

Foreground

bg-foreground

Primary

bg-primary

Secondary

bg-secondary

Muted

bg-muted

Accent

bg-accent

Destructive

bg-destructive

Card

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-border
border-primary
border-secondary

Border Radius

rounded-sm
rounded-md
rounded-lg
rounded-xl

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

NameTypeStatusCreated Date
Acme FinancialHOME_OFFICEActiveJan 15, 2024
Wealth Advisors CoDEFAULTActiveFeb 3, 2024
Investment Partners LLCDEFAULTPendingMar 12, 2024
Global Finance GroupHOME_OFFICEInactiveApr 8, 2024
Premier WealthDEFAULTErrorMay 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 NameEmail AddressStatus
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 truncate class to ALL content divs inside cells
  • Add title attribute 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>
  );
}