UI Components
Shared component library with Button, Card, Input, Toast, and theming support.
Overview
ScaleRocket ships a shared component library in packages/ui/. Built on top of Tailwind CSS and inspired by shadcn/ui, these components are used across all three apps.
Available Components
Button
import { Button } from "@saas/ui";
<Button variant="default">Primary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="destructive">Delete</Button>
<Button variant="link">Link style</Button>
<Button size="sm">Small</Button>
<Button size="lg">Large</Button>
<Button disabled>Disabled</Button>
<Button loading>Saving...</Button>Props:
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default" | "outline" | "ghost" | "destructive" | "link" | "default" | Visual style |
size | "sm" | "default" | "lg" | "default" | Button size |
loading | boolean | false | Shows spinner and disables button |
disabled | boolean | false | Disables interaction |
Card
import { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter } from "@saas/ui";
<Card>
<CardHeader>
<CardTitle>Plan Name</CardTitle>
<CardDescription>Monthly subscription</CardDescription>
</CardHeader>
<CardContent>
<p>$29/month</p>
</CardContent>
<CardFooter>
<Button>Subscribe</Button>
</CardFooter>
</Card>Input
import { Input } from "@saas/ui";
<Input type="email" placeholder="you@example.com" />
<Input type="password" placeholder="Password" />
<Input disabled value="Read only" />Props: Extends native <input> props plus:
| Prop | Type | Description |
|---|---|---|
error | string | Displays error message below input |
label | string | Label text above input |
Toast
import { useToast } from "@saas/ui";
const { toast } = useToast();
// Success
toast({ title: "Saved!", description: "Your changes have been saved." });
// Error
toast({ title: "Error", description: "Something went wrong.", variant: "destructive" });Wrap your app with the Toaster provider:
import { Toaster } from "@saas/ui";
function App() {
return (
<>
<YourApp />
<Toaster />
</>
);
}ThemeProvider
Provides light/dark mode support across the app:
import { ThemeProvider } from "@saas/ui";
<ThemeProvider defaultTheme="system" storageKey="scalerocket-theme">
<App />
</ThemeProvider>Props:
| Prop | Type | Default | Description |
|---|---|---|---|
defaultTheme | "light" | "dark" | "system" | "system" | Initial theme |
storageKey | string | "theme" | localStorage key for persistence |
ThemeToggle
A dropdown button to switch between light, dark, and system themes:
import { ThemeToggle } from "@saas/ui";
<ThemeToggle />Usage Across Apps
Import components from @saas/ui in any app:
// apps/app/src/pages/dashboard.tsx
import { Button, Card, CardContent } from "@saas/ui";The package is linked via the pnpm workspace -- no publishing needed.
Variants and Customization
Components use Tailwind CSS classes and CSS variables for theming. Customize the design system by editing:
/* packages/ui/src/globals.css */
:root {
--background: 0 0% 100%;
--foreground: 0 0% 3.9%;
--primary: 0 0% 9%;
--primary-foreground: 0 0% 98%;
--muted: 0 0% 96.1%;
--muted-foreground: 0 0% 45.1%;
--destructive: 0 84.2% 60.2%;
--border: 0 0% 89.8%;
--radius: 0.5rem;
}
.dark {
--background: 0 0% 3.9%;
--foreground: 0 0% 98%;
--primary: 0 0% 98%;
--primary-foreground: 0 0% 9%;
/* ... */
}Adding New Components
- Create the component in
packages/ui/src/components/:
// packages/ui/src/components/badge.tsx
import { cn } from "../lib/utils";
interface BadgeProps {
variant?: "default" | "success" | "warning" | "error";
children: React.ReactNode;
}
export function Badge({ variant = "default", children }: BadgeProps) {
return (
<span
className={cn(
"inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium",
variant === "default" && "bg-primary/10 text-primary",
variant === "success" && "bg-green-100 text-green-800",
variant === "warning" && "bg-yellow-100 text-yellow-800",
variant === "error" && "bg-red-100 text-red-800"
)}
>
{children}
</span>
);
}- Export it from
packages/ui/src/index.ts:
export { Badge } from "./components/badge";- Use it in any app:
import { Badge } from "@saas/ui";
<Badge variant="success">Active</Badge>Dark Mode
Dark mode works automatically with the ThemeProvider. All components respect the current theme via CSS variables.
To conditionally style in dark mode with Tailwind:
<div className="bg-white dark:bg-gray-900">
<p className="text-gray-900 dark:text-gray-100">Adapts to theme</p>
</div>Access the current theme programmatically:
import { useTheme } from "@saas/ui";
const { theme, setTheme } = useTheme();
// theme: "light" | "dark" | "system"Done reading? Mark this page as complete.