UI Components

Starterbase includes 25+ reusable UI components built with Headless UI, Radix UI, and Tailwind CSS. All components support dark mode and are fully accessible.

Quick Start

Import components from @/components/ui:

import { Button, Input, Card, Badge, Dialog } from '@/components/ui';

export default function MyPage() {
  return (
    <Card>
      <Input label="Email" placeholder="Enter your email" />
      <Button color="blue">Submit</Button>
    </Card>
  );
}

Component Categories

Form Components

Component Description Key Props
Button Action button with 20+ color variants color, outline, plain, size, href
Input Text input with icons and validation label, error, leftIcon, rightIcon
Textarea Multi-line text input label, error, helperText
Select Native select dropdown label, error, helperText
Checkbox Checkbox with loading state label, error, isLoading, size
Switch Toggle switch label, description, checked
SearchableSelect Combobox with search options, value, onChange
Combobox Advanced autocomplete options, filter, displayValue

Layout Components

Component Description Key Props
Card Container with variants variant, accent
Dialog Modal dialog isOpen, onClose, size
Tabs Tab navigation tabs, defaultIndex
Accordion Collapsible sections Radix-based
Sidebar Navigation sidebar SidebarHeader, SidebarBody, SidebarItem
SidebarLayout Layout with sidebar Wraps content with sidebar
Navbar Top navigation bar NavbarSection, NavbarItem

Data Display

Component Description Key Props
Table Basic data table shouldStretch
DataTable Advanced table with TanStack columns, data, enableGlobalFilter
Badge Status badges variant, size
Avatar User avatar with fallback size, name, src
StatCard Statistics display title, value, trend, icon, iconBgColor, loading

Feedback Components

Component Description Key Props
Spinner Loading spinner size
Skeleton Loading placeholder className
Progress Progress bar value, variant, size, animated
Alert Alert messages variant, title
EmptyState Empty state placeholder icon, title, description, action

Navigation

Component Description Key Props
Breadcrumb Navigation breadcrumb items, separator
Pagination Page navigation currentPage, totalPages, onPageChange
Dropdown Dropdown menu trigger, align, position

Utility Components

Component Description
Link Internal link wrapper
InputGroup Groups inputs together
useToast Toast notification hook

Table Cell Components

Pre-built cell renderers for DataTable:

Component Description
StatusBadgeCell Colored status badge
DateCell Formatted date display
CodeCell Monospace code display

Usage Examples

Form with Validation

'use client';
import { useState } from 'react';
import { Input, Button, Select, Textarea } from '@/components/ui';

export default function ContactForm() {
  const [email, setEmail] = useState('');
  const [error, setError] = useState('');

  const handleSubmit = () => {
    if (!email.includes('@')) {
      setError('Please enter a valid email');
      return;
    }
    // Submit form
  };

  return (
    <form className="space-y-4">
      <Input
        label="Email"
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        error={error}
        placeholder="you@example.com"
      />
      <Select label="Subject">
        <option value="">Select a topic</option>
        <option value="support">Support</option>
        <option value="sales">Sales</option>
      </Select>
      <Textarea
        label="Message"
        placeholder="How can we help?"
        helperText="We'll respond within 24 hours"
      />
      <Button color="blue" onClick={handleSubmit}>
        Send Message
      </Button>
    </form>
  );
}

Data Table with Filtering

'use client';
import { DataTable, Badge } from '@/components/ui';
import type { ColumnDef } from '@tanstack/react-table';

interface User {
  id: string;
  name: string;
  email: string;
  status: 'active' | 'inactive';
}

const columns: ColumnDef<User>[] = [
  { accessorKey: 'name', header: 'Name' },
  { accessorKey: 'email', header: 'Email' },
  {
    accessorKey: 'status',
    header: 'Status',
    cell: ({ row }) => (
      <Badge variant={row.original.status === 'active' ? 'success' : 'default'}>
        {row.original.status}
      </Badge>
    ),
  },
];

export default function UsersTable({ users }: { users: User[] }) {
  return (
    <DataTable
      columns={columns}
      data={users}
      enableGlobalFilter
      enableFilterBuilder
    />
  );
}

Modal Dialog

'use client';
import { useState } from 'react';
import { Button, Dialog, DialogTitle, DialogDescription } from '@/components/ui';

export default function ConfirmDialog() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <Button onClick={() => setIsOpen(true)}>Delete Item</Button>

      <Dialog isOpen={isOpen} onClose={() => setIsOpen(false)} size="sm">
        <DialogTitle>Confirm Delete</DialogTitle>
        <DialogDescription>
          Are you sure? This action cannot be undone.
        </DialogDescription>
        <div className="mt-4 flex gap-3 justify-end">
          <Button outline onClick={() => setIsOpen(false)}>
            Cancel
          </Button>
          <Button color="red" onClick={() => setIsOpen(false)}>
            Delete
          </Button>
        </div>
      </Dialog>
    </>
  );
}

Statistics Dashboard

import { StatCard } from '@/components/ui';
import { UsersIcon, CurrencyDollarIcon } from '@heroicons/react/24/outline';

export default function Dashboard() {
  return (
    <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
      <StatCard
        title="Total Users"
        value="12,345"
        icon={<UsersIcon className="h-6 w-6" />}
        iconBgColor="blue"
        trend={{ value: 12, direction: 'up', label: 'vs last month' }}
      />
      <StatCard
        title="Revenue"
        value="$48,200"
        icon={<CurrencyDollarIcon className="h-6 w-6" />}
        iconBgColor="green"
        trend={{ value: 8, direction: 'up', label: 'vs last month' }}
      />
    </div>
  );
}

Loading State with StatCard

<StatCard
  title="Total Users"
  value="0"
  loading={isLoading}  // Shows skeleton when loading
/>

Button Colors

The Button component supports 20+ color variants:

// Solid colors
<Button color="blue">Blue</Button>
<Button color="red">Red</Button>
<Button color="green">Green</Button>
<Button color="purple">Purple</Button>
<Button color="orange">Orange</Button>
<Button color="indigo">Indigo</Button>
<Button color="pink">Pink</Button>
<Button color="cyan">Cyan</Button>
<Button color="amber">Amber</Button>
<Button color="emerald">Emerald</Button>
<Button color="teal">Teal</Button>
<Button color="sky">Sky</Button>
<Button color="violet">Violet</Button>
<Button color="fuchsia">Fuchsia</Button>
<Button color="rose">Rose</Button>
<Button color="lime">Lime</Button>
<Button color="yellow">Yellow</Button>
<Button color="zinc">Zinc</Button>
<Button color="dark">Dark</Button>
<Button color="white">White</Button>
<Button color="light">Light</Button>
<Button color="dark/zinc">Dark/Zinc</Button>
<Button color="dark/white">Dark/White</Button>

// Variants
<Button outline>Outline</Button>
<Button plain>Plain</Button>

// Sizes
<Button size="xs">Extra Small</Button>
<Button size="sm">Small</Button>
<Button size="md">Medium (default)</Button>

// As link
<Button href="/dashboard">Go to Dashboard</Button>

Dark Mode Support

All components automatically support dark mode. Use Tailwind's dark: prefix for custom styling:

<Card className="bg-white dark:bg-zinc-900">
  <p className="text-zinc-900 dark:text-zinc-100">
    Dark mode ready content
  </p>
</Card>

Customization

Components accept a className prop for custom styling:

<Button className="w-full" color="blue">
  Full Width Button
</Button>

<Card className="p-8 border-2 border-blue-500">
  Custom Card
</Card>

Accessibility

All components follow WAI-ARIA guidelines:

Dependencies

Package Used For
Headless UI Dialog, Menu, Switch, Tabs, Combobox
Radix UI Accordion
TanStack Table DataTable
Tailwind CSS Styling
clsx / tailwind-merge Class utilities