Skip to main content

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

CategoryComponents
FormButton, Input, Textarea, Select, Checkbox, RadioGroup, Switch, Slider, Label
DisplayCard, Badge, Alert, Avatar, Skeleton, Progress, Table, Tabs, Breadcrumb, ScrollArea
OverlayDialog, AlertDialog, Sheet, Popover, Tooltip, DropdownMenu, ContextMenu
FeedbackToast, Toaster, Sonner
AdvancedCommand, Carousel, Collapsible, Resizable

Category Guides

CategoryDescriptionGo to
Form ComponentsButtons, inputs, selects, checkboxes, switches, slidersView →
Display ComponentsCards, badges, alerts, avatars, tables, tabsView →
Overlay ComponentsDialogs, sheets, popovers, tooltips, menusView →
Feedback ComponentsToast notifications (Toast & Sonner)View →
Advanced ComponentsCommand palette, carousel, collapsible, resizable panelsView →

Quick Preview

Live Editor
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>
  );
}
Result
Loading...

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

PropTypeDefaultDescription
defaultThemelight | dark | systemsystemInitial theme
storageKeystringcpod-themeLocalStorage key
childrenReactNode-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.