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:
- Keyboard navigation support
- Screen reader friendly
- Focus management
- ARIA labels and roles
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 |