ScaleRocket/Web

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:

PropTypeDefaultDescription
variant"default" | "outline" | "ghost" | "destructive" | "link""default"Visual style
size"sm" | "default" | "lg""default"Button size
loadingbooleanfalseShows spinner and disables button
disabledbooleanfalseDisables 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:

PropTypeDescription
errorstringDisplays error message below input
labelstringLabel 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:

PropTypeDefaultDescription
defaultTheme"light" | "dark" | "system""system"Initial theme
storageKeystring"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

  1. 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>
  );
}
  1. Export it from packages/ui/src/index.ts:
export { Badge } from "./components/badge";
  1. 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.

On this page