| name | backstage-style-web |
| description | Generate enterprise-grade web applications using Backstage Design System. Create admin dashboards, developer tools, and internal applications with modern React components, dark/light themes, and responsive design patterns based on Radix UI and Tailwind CSS. |
Backstage Style Web Generator
Overview
Create professional, enterprise-grade web applications using the Backstage Design System. This skill generates modern React applications with TypeScript, featuring comprehensive UI components, dark/light theme support, responsive design, and accessibility-first patterns. Perfect for building admin dashboards, developer tools, internal applications, and data management interfaces.
Backstage Design System Implementation Guide
Core Architecture Overview
The Backstage Design System is built on modern React patterns and industry-standard libraries:
Technology Stack
- React 18+ with TypeScript
- Radix UI Primitives for accessible, headless components
- Tailwind CSS for utility-first styling
- Class Variance Authority (CVA) for type-safe component variants
- React Hook Form with Zod validation
- Lucide React for consistent iconography
Key Design Principles
- Accessibility First: Built on Radix UI primitives with ARIA support
- Type Safety: Full TypeScript coverage with strict typing
- Composability: Components designed for flexible composition
- Consistency: Unified design tokens and patterns
- Performance: Optimized for bundle size and runtime performance
Component Architecture Patterns
1. Compound Components
Components are designed with multiple sub-components for maximum flexibility:
<Card>
<CardHeader>
<CardTitle>Title</CardTitle>
<CardDescription>Description</CardDescription>
<CardAction>Action buttons</CardAction>
</CardHeader>
<CardContent>
Main content
</CardContent>
<CardFooter>
Footer content
</CardFooter>
</Card>
2. Variant-Based Styling
Using CVA for type-safe, predictable component variants:
const buttonVariants = cva(
"inline-flex items-center justify-center rounded-md text-sm font-medium",
{
variants: {
variant: {
default: "bg-primary text-primary-foreground hover:bg-primary/90",
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
outline: "border border-input bg-background hover:bg-accent",
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
}
);
3. Data Attributes for Styling
Consistent use of data attributes for component identification and styling:
<div
data-slot="card"
className="bg-card text-card-foreground rounded-lg border"
>
<div data-slot="card-header">
{/* Header content */}
</div>
</div>
Theme System Implementation
1. Color Architecture
Brand Colors (11-step scale)
:root {
--brand-050: #F5F1F0;
--brand-100: #E9DDDB;
--brand-200: #D6BEBB;
--brand-300: #B78F8A;
--brand-400: #94635E;
--brand-500: #6A4040;
--brand-600: #5B3535;
--brand-700: #4C2D2D;
--brand-800: #3E2525;
--brand-900: #2E1C1C;
--brand-950: #1C1010;
}
Semantic Color Tokens
:root {
--background: hsl(48, 33%, 98%);
--foreground: hsl(0, 25%, 33%);
--card: hsl(48, 33%, 98%);
--card-foreground: hsl(0, 25%, 33%);
--popover: hsl(48, 33%, 98%);
--popover-foreground: hsl(0, 25%, 33%);
--primary: hsl(222, 28%, 14%);
--primary-foreground: hsl(48, 33%, 98%);
--secondary: hsl(210, 25%, 96%);
--secondary-foreground: hsl(0, 25%, 33%);
--muted: hsl(210, 25%, 96%);
--muted-foreground: hsl(215, 9%, 46%);
--accent: hsl(210, 25%, 96%);
--accent-foreground: hsl(0, 25%, 33%);
--destructive: hsl(0, 82%, 67%);
--destructive-foreground: hsl(48, 33%, 98%);
--border: hsl(0, 14%, 94%);
--input: hsl(214, 27%, 91%);
--ring: hsl(0, 25%, 33%);
}
[data-theme='dark'] {
--background: hsl(0, 25%, 6%);
--foreground: hsl(48, 33%, 98%);
--card: hsl(0, 25%, 6%);
--card-foreground: hsl(48, 33%, 98%);
--popover: hsl(0, 25%, 6%);
--popover-foreground: hsl(48, 33%, 98%);
--primary: hsl(48, 33%, 98%);
--primary-foreground: hsl(0, 25%, 33%);
--secondary: hsl(0, 22%, 14%);
--secondary-foreground: hsl(48, 33%, 98%);
--muted: hsl(0, 22%, 14%);
--muted-foreground: hsl(0, 20%, 75%);
--accent: hsl(0, 22%, 14%);
--accent-foreground: hsl(48, 33%, 98%);
--destructive: hsl(0, 82%, 67%);
--destructive-foreground: hsl(48, 33%, 98%);
--border: hsl(0, 22%, 14%);
--input: hsl(0, 22%, 14%);
--ring: hsl(0, 25%, 33%);
}
2. Font Families
@font-face {
font-family: 'Instrument Serif';
src: url('./references/InstrumentSerif-Regular.ttf') format('truetype');
font-weight: 400;
font-style: normal;
}
@font-face {
font-family: 'Instrument Serif';
src: url('./references/InstrumentSerif-Italic.ttf') format('truetype');
font-weight: 400;
font-style: italic;
}
p, .text-body, .text-content {
font-family: 'Poppins', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}
h1, h2, h3, h4, h5, h6,
.heading-1, .heading-2, .heading-3, .heading-4, .heading-5, .heading-6 {
font-family: 'Instrument Serif', Georgia, 'Times New Roman', serif;
font-weight: 400;
}
h1 .preposition, h2 .preposition, h3 .preposition,
h4 .preposition, h5 .preposition, h6 .preposition,
.heading-1 .preposition, .heading-2 .preposition, .heading-3 .preposition,
.heading-4 .preposition, .heading-5 .preposition, .heading-6 .preposition {
font-style: italic;
}
3. Typography Scale
.text-xxs { font-size: 8px; }
.text-xs { font-size: 10px; }
.text-sm { font-size: 12px; }
.text-base { font-size: 14px; }
.text-lg { font-size: 16px; }
.display-xl { font-size: 60px; }
4. Spacing System (4px base unit)
.space-1 { margin: 4px; }
.space-2 { margin: 8px; }
.space-3 { margin: 12px; }
.space-4 { margin: 16px; }
.space-6 { margin: 24px; }
.space-8 { margin: 32px; }
.space-16 { margin: 64px; }
Responsive Design Strategy
1. Breakpoint System
sm: '640px',
md: '768px',
lg: '1024px',
xl: '1280px',
2xl: '1536px'
2. Component Responsiveness
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{}
</div>
const isMobile = useIsMobile();
3. Sidebar Adaptation
{isMobile ? (
<Sheet open={openMobile} onOpenChange={setOpenMobile}>
<SheetContent side="left" className="p-0">
<SidebarContent />
</SheetContent>
</Sheet>
) : (
<Sidebar className={cn(
"transition-all duration-300",
state === "collapsed" ? "w-[48px]" : "w-[256px]"
)}>
<SidebarContent />
</Sidebar>
)}
Accessibility Implementation
1. ARIA Patterns
<button
aria-label="Close dialog"
aria-expanded={isOpen}
aria-controls="dialog-content"
>
<X className="h-4 w-4" />
</button>
<label htmlFor="email" className="sr-only">
Email address
</label>
<input
id="email"
type="email"
aria-describedby="email-description"
aria-invalid={hasError}
/>
<div id="email-description" className="text-sm text-muted-foreground">
We'll never share your email
</div>
2. Keyboard Navigation
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (event.key === 'Escape') {
onClose();
}
if (event.key === 'Enter' || event.key === ' ') {
onActivate();
}
};
document.addEventListener('keydown', handleKeyDown);
return () => document.removeEventListener('keydown', handleKeyDown);
}, [onClose, onActivate]);
3. Focus Management
import { FocusTrap } from '@radix-ui/react-focus-trap';
<FocusTrap asChild>
<div className="modal-content">
{/* Modal content with proper focus order */}
</div>
</FocusTrap>
Form Architecture
1. React Hook Form Integration
import { useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import * as z from "zod";
const formSchema = z.object({
email: z.string().email("Invalid email address"),
password: z.string().min(8, "Password must be at least 8 characters"),
});
type FormData = z.infer<typeof formSchema>;
const form = useForm<FormData>({
resolver: zodResolver(formSchema),
defaultValues: {
email: "",
password: "",
},
});
2. Form Field Component Pattern
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input placeholder="Enter your email" {...field} />
</FormControl>
<FormDescription>
We'll use this to send you updates
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
State Management Patterns
1. Component State
const [isOpen, setIsOpen] = useState(false);
const [selectedItems, setSelectedItems] = useState<string[]>([]);
const hasSelection = selectedItems.length > 0;
const allSelected = selectedItems.length === items.length;
2. Context for Shared State
const ThemeContext = createContext<{
theme: Theme;
setTheme: (theme: Theme) => void;
} | null>(null);
const SidebarContext = createContext<{
state: "expanded" | "collapsed";
open: boolean;
setOpen: (open: boolean) => void;
isMobile: boolean;
} | null>(null);
3. URL State Management
const [searchParams, setSearchParams] = useSearchParams();
const currentPage = Number(searchParams.get('page')) || 1;
const searchQuery = searchParams.get('q') || '';
const updateFilters = (filters: Record<string, string>) => {
const newParams = new URLSearchParams(searchParams);
Object.entries(filters).forEach(([key, value]) => {
if (value) {
newParams.set(key, value);
} else {
newParams.delete(key);
}
});
setSearchParams(newParams);
};
Performance Optimization
1. Code Splitting
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Settings = lazy(() => import('./pages/Settings'));
<Suspense fallback={<LoadingSpinner />}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
2. Memoization
const processedData = useMemo(() => {
return data.map(item => ({
...item,
computed: expensiveComputation(item)
}));
}, [data]);
const handleItemClick = useCallback((id: string) => {
setSelectedItems(prev =>
prev.includes(id)
? prev.filter(item => item !== id)
: [...prev, id]
);
}, []);
const MemoizedTableRow = memo(TableRow);
3. Virtual Scrolling (for large lists)
import { FixedSizeList as List } from 'react-window';
const VirtualizedTable = ({ items }: { items: any[] }) => {
const Row = ({ index, style }: { index: number; style: React.CSSProperties }) => (
<div style={style}>
<TableRow data={items[index]} />
</div>
);
return (
<List
height={600}
itemCount={items.length}
itemSize={50}
width="100%"
>
{Row}
</List>
);
};
Testing Patterns
1. Component Testing
import { render, screen, fireEvent } from '@testing-library/react';
import { Button } from './button';
describe('Button', () => {
it('renders with correct variant styles', () => {
render(<Button variant="destructive">Delete</Button>);
const button = screen.getByRole('button');
expect(button).toHaveClass('bg-destructive');
});
it('handles click events', () => {
const handleClick = jest.fn();
render(<Button onClick={handleClick}>Click me</Button>);
fireEvent.click(screen.getByRole('button'));
expect(handleClick).toHaveBeenCalledTimes(1);
});
});
2. Accessibility Testing
import { axe, toHaveNoViolations } from 'jest-axe';
expect.extend(toHaveNoViolations);
it('should not have accessibility violations', async () => {
const { container } = render(<MyComponent />);
const results = await axe(container);
expect(results).toHaveNoViolations();
});
This implementation guide provides the foundation for building consistent, accessible, and performant applications using the Backstage Design System.