React Components
@cpod/react provides 40+ pre-built, accessible React components with CyberPod styling for building consistent user interfaces.
Installation
npm install @cpod/react
# or
pnpm add @cpod/react
# or
yarn add @cpod/react
Setup
1. Import Styles
Import the CSS file in your root component or _app.tsx:
import "@cpod/react/styles.css";
2. Wrap with ThemeProvider
import { ThemeProvider } from "@cpod/react";
function App() {
return (
<ThemeProvider>
<YourApp />
</ThemeProvider>
);
}
Component Overview
All Components at a Glance
| Category | Components |
|---|---|
| Form | Button, Input, Textarea, Select, Checkbox, RadioGroup, Switch, Slider, Label |
| Display | Card, Badge, Alert, Avatar, Skeleton, Progress, Table, Tabs, Breadcrumb, ScrollArea |
| Overlay | Dialog, AlertDialog, Sheet, Popover, Tooltip, DropdownMenu, ContextMenu |
| Feedback | Toast, Toaster, Sonner |
| Advanced | Command, Carousel, Collapsible, Resizable |
Category Guides
| Category | Description | Go to |
|---|---|---|
| Form Components | Buttons, inputs, selects, checkboxes, switches, sliders | View → |
| Display Components | Cards, badges, alerts, avatars, tables, tabs | View → |
| Overlay Components | Dialogs, sheets, popovers, tooltips, menus | View → |
| Feedback Components | Toast notifications (Toast & Sonner) | View → |
| Advanced Components | Command palette, carousel, collapsible, resizable panels | View → |
Quick Preview
function QuickPreview() { const [count, setCount] = React.useState(0); const [checked, setChecked] = React.useState(false); return ( <div style={{ display: 'flex', flexDirection: 'column', gap: '16px', maxWidth: '400px' }}> <div style={{ padding: '20px', borderRadius: '12px', border: '1px solid #e2e8f0', background: 'white', }}> <h4 style={{ margin: 0, marginBottom: '8px' }}>CyberPod UI Components</h4> <p style={{ margin: 0, color: '#64748b', fontSize: '14px', marginBottom: '16px' }}> Beautiful, accessible components for your apps. </p> <div style={{ display: 'flex', gap: '8px', marginBottom: '16px' }}> <button onClick={() => setCount(c => c + 1)} style={{ padding: '8px 16px', borderRadius: '8px', background: 'linear-gradient(135deg, #8b5cf6 0%, #6366f1 100%)', color: 'white', border: 'none', cursor: 'pointer', fontWeight: 600, fontSize: '14px', }} > Count: {count} </button> <button style={{ padding: '8px 16px', borderRadius: '8px', background: 'white', border: '1px solid #e2e8f0', cursor: 'pointer', fontWeight: 600, fontSize: '14px', }} > Secondary </button> </div> <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}> <input type="checkbox" checked={checked} onChange={(e) => setChecked(e.target.checked)} style={{ width: '16px', height: '16px', accentColor: '#8b5cf6' }} /> <span style={{ fontSize: '14px' }}>Enable notifications</span> </div> </div> <div style={{ display: 'flex', gap: '8px' }}> <span style={{ padding: '4px 10px', borderRadius: '9999px', background: '#8b5cf6', color: 'white', fontSize: '12px', fontWeight: 500, }}>New</span> <span style={{ padding: '4px 10px', borderRadius: '9999px', background: '#dcfce7', color: '#16a34a', fontSize: '12px', fontWeight: 500, }}>Success</span> <span style={{ padding: '4px 10px', borderRadius: '9999px', background: '#fee2e2', color: '#dc2626', fontSize: '12px', fontWeight: 500, }}>Error</span> </div> </div> ); }
Quick Import Reference
Copy these imports for common use cases:
// Basic form
import { Button, Input, Label, Checkbox } from "@cpod/react";
// Card layout
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@cpod/react";
// Dialog/Modal
import { Dialog, DialogTrigger, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@cpod/react";
// Table
import { Table, TableHeader, TableBody, TableRow, TableHead, TableCell } from "@cpod/react";
// Toast notifications
import { Toaster, useToast } from "@cpod/react";
// or with Sonner
import { Sonner } from "@cpod/react";
import { toast } from "sonner";
// All core components
import {
Button,
Input,
Textarea,
Select,
SelectTrigger,
SelectValue,
SelectContent,
SelectItem,
Checkbox,
RadioGroup,
RadioGroupItem,
Switch,
Slider,
Label,
Card,
Badge,
Alert,
Avatar,
Skeleton,
Progress,
Tabs,
TabsList,
TabsTrigger,
TabsContent,
Dialog,
Sheet,
Popover,
Tooltip,
TooltipProvider,
DropdownMenu,
Command,
} from "@cpod/react";
ThemeProvider
Manages light/dark theme and provides theme utilities.
Features
- System preference detection
- Manual theme toggle
- LocalStorage persistence
- Custom theme overrides via CSS variables
Usage
import { ThemeProvider, useTheme } from "@cpod/react";
function App() {
return (
<ThemeProvider defaultTheme="system" storageKey="app-theme">
<YourApp />
</ThemeProvider>
);
}
// In a component
function ThemeToggle() {
const { theme, setTheme } = useTheme();
return (
<Button onClick={() => setTheme(theme === "dark" ? "light" : "dark")}>
Toggle Theme
</Button>
);
}
Props
| Prop | Type | Default | Description |
|---|---|---|---|
defaultTheme | light | dark | system | system | Initial theme |
storageKey | string | cpod-theme | LocalStorage key |
children | ReactNode | - | App content |
Integration Examples
Next.js App Router
// app/layout.tsx
import "@cpod/react/styles.css";
import { ThemeProvider } from "@cpod/react";
export default function RootLayout({ children }) {
return (
<html lang="en" suppressHydrationWarning>
<body>
<ThemeProvider defaultTheme="system">
{children}
</ThemeProvider>
</body>
</html>
);
}
// app/page.tsx
import { Button, Card, CardContent } from "@cpod/react";
export default function Home() {
return (
<Card>
<CardContent>
<Button>Get Started</Button>
</CardContent>
</Card>
);
}
Next.js Pages Router
// pages/_app.tsx
import "@cpod/react/styles.css";
import { ThemeProvider } from "@cpod/react";
export default function App({ Component, pageProps }) {
return (
<ThemeProvider>
<Component {...pageProps} />
</ThemeProvider>
);
}
Vite + React
// main.tsx
import "@cpod/react/styles.css";
import { ThemeProvider } from "@cpod/react";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
<ThemeProvider>
<App />
</ThemeProvider>
</React.StrictMode>
);
Best Practices
1. Use Semantic Variants
Choose button variants that match the action's importance:
// ✅ Good
<Button variant="destructive">Delete Account</Button>
<Button variant="outline">Cancel</Button>
// ❌ Avoid
<Button>Delete Account</Button> // Too subtle for destructive action
2. Consistent Sizing
Use the same size across related components:
// ✅ Good
<Input size="lg" />
<Button size="lg">Submit</Button>
// ❌ Avoid mixing sizes in the same form
<Input size="sm" />
<Button size="lg">Submit</Button>
3. Loading States
Always disable buttons during loading:
// ✅ Good
<Button loading disabled onClick={handleSubmit}>
Save
</Button>
// ❌ Missing disabled
<Button loading onClick={handleSubmit}>
Save
</Button>
4. Error Feedback
Use error states with helpful messages:
// ✅ Good
<div>
<Input error value={email} onChange={setEmail} />
{emailError && <span className="text-red-500">{emailError}</span>}
</div>
Customization
All components use CSS variables from @cpod/tokens. Override them to customize:
:root {
--cpod-primary: #your-color;
--cpod-radius: 8px;
}
See the Design Tokens guide for all available variables.
TypeScript Support
All components are fully typed with TypeScript. Import types:
import type { ButtonProps, InputProps } from "@cpod/react";
const MyButton: React.FC<ButtonProps> = (props) => {
return <Button {...props} />;
};
Accessibility
All components follow accessibility best practices:
- ✅ Proper ARIA labels
- ✅ Keyboard navigation
- ✅ Focus indicators
- ✅ Screen reader support
- ✅ Color contrast (WCAG AA)
Based on Radix UI primitives for maximum accessibility.