Components Reference
Complete guide to the Constellation component library and patterns.
Component Organization
src/components/
โโโ ui/ # Shadcn/ui base components
โโโ common/ # Shared across features
โโโ admin/ # Admin-specific components
โโโ dashboard/ # Dashboard feature
โโโ editor/ # Editor feature
โโโ forms/ # Form components
โโโ graph/ # Graph visualization
โโโ mapEditor/ # Map editor
โโโ navigation/ # Navigation
โโโ plate-ui/ # Editor plugins
โโโ context/ # Context providers
UI Component Library (Shadcn/ui)
Base components imported from Shadcn/ui at src/components/ui/.
Available Components
| Component | Location | Use Case |
|---|---|---|
| Button | ui/Button |
Clickable buttons |
| Card | ui/Card |
Content containers |
| Dialog | ui/Dialog |
Modal dialogs |
| Form | ui/Form |
Form wrapper |
| Input | ui/Input |
Text input fields |
| Select | ui/Select |
Dropdown selection |
| Tabs | ui/Tabs |
Tabbed content |
| Alert | ui/Alert |
Alert messages |
| Badge | ui/Badge |
Status labels |
| Dropdown | ui/Dropdown |
Dropdown menus |
Button Component
import { Button } from '@/src/components/ui/Button';
// Basic button
<Button>Click me</Button>
// Variants
<Button variant="destructive">Delete</Button>
<Button variant="outline">Secondary</Button>
<Button variant="ghost">Tertiary</Button>
// Sizes
<Button size="sm">Small</Button>
<Button size="lg">Large</Button>
// States
<Button disabled>Disabled</Button>
<Button isLoading>Loading...</Button>
// Full width
<Button className="w-full">Full width</Button>
Card Component
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/src/components/ui/Card';
<Card>
<CardHeader>
<CardTitle>Title</CardTitle>
<CardDescription>Description</CardDescription>
</CardHeader>
<CardContent>
Content here
</CardContent>
</Card>
Form Component
import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { Form, FormControl, FormField, FormItem, FormLabel } from '@/src/components/ui/Form';
import { Input } from '@/src/components/ui/Input';
const formSchema = z.object({
email: z.string().email(),
name: z.string().min(2),
});
export function MyForm() {
const form = useForm({
resolver: zodResolver(formSchema),
});
return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}>
<FormField
control={form.control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input placeholder="Email" {...field} />
</FormControl>
</FormItem>
)}
/>
</form>
</Form>
);
}
Common Components
Header
Located: src/components/common/Header.tsx
import { Header } from '@/src/components/common/Header';
<Header />
Props: None (uses context for auth state)
Features: - User menu - Logo - Navigation links - Dark mode toggle
Navigation
Located: src/components/common/Navigation.tsx
import { Navigation } from '@/src/components/common/Navigation';
<Navigation />
Footer
Located: src/components/common/Footer.tsx
import { Footer } from '@/src/components/common/Footer';
<Footer />
Dashboard Components
DashboardLayout
import { DashboardLayout } from '@/src/components/dashboard/DashboardLayout';
<DashboardLayout>
{/* Dashboard content */}
</DashboardLayout>
Props:
- children - Dashboard content
WorkspaceCard
interface WorkspaceCardProps {
workspace: Workspace;
onSelect?: (workspace: Workspace) => void;
onDelete?: (workspaceId: string) => void;
}
<WorkspaceCard
workspace={workspace}
onSelect={handleSelect}
onDelete={handleDelete}
/>
Features: - Workspace thumbnail - Name and description - Last modified date - Actions menu
StatCard
<StatCard
title="Total Projects"
value={42}
icon={<ProjectIcon />}
trend="+12%"
/>
Editor Components (Plate.js)
PlateEditor
Main editor component:
import { PlateEditor } from '@/src/components/editor/PlateEditor';
<PlateEditor
content={content}
onChange={handleChange}
readOnly={false}
/>
Props:
- content - Initial editor content
- onChange - Callback on content change
- readOnly - Disable editing
- plugins - Custom plugins array
EditorToolbar
import { EditorToolbar } from '@/src/components/editor/EditorToolbar';
<EditorToolbar />
Features: - Text formatting (bold, italic, underline) - Lists and indentation - Link insertion - Code blocks - Mentions and emojis
Plate Plugins
Available plugins in src/components/plate-ui/:
| Plugin | Description |
|---|---|
BoldPlugin |
Bold text formatting |
ItalicPlugin |
Italic text formatting |
UnderlinePlugin |
Underline text |
CodePlugin |
Inline code |
BlockquotePlugin |
Block quotes |
ListPlugin |
Ordered/unordered lists |
LinkPlugin |
Hyperlinks |
ImagePlugin |
Image insertion |
MentionPlugin |
@mentions |
EmojiPlugin |
Emoji picker |
SlashCommandPlugin |
Slash commands |
TablePlugin |
Table insertion |
CodeBlockPlugin |
Code blocks |
Admin Components
UserManagement
import { UserManagement } from '@/src/components/admin/UserManagement';
<UserManagement />
Features: - User list with pagination - Create/edit/delete users - Role management - Search and filter
ContentModeration
import { ContentModeration } from '@/src/components/admin/ContentModeration';
<ContentModeration />
Features: - Review reported content - Approve/reject content - Flag management
SystemSettings
import { SystemSettings } from '@/src/components/admin/SystemSettings';
<SystemSettings />
Features: - Global configuration - Feature flags - Notification settings
Graph Components
GraphViewer
import { GraphViewer } from '@/src/components/graph/GraphViewer';
interface Node {
id: string;
label: string;
}
interface Edge {
source: string;
target: string;
}
<GraphViewer
nodes={nodes}
edges={edges}
onNodeClick={handleNodeClick}
interactive={true}
/>
GraphEditor
import { GraphEditor } from '@/src/components/graph/GraphEditor';
<GraphEditor
graph={graph}
onChange={handleChange}
/>
Form Components
UserForm
import { UserForm } from '@/src/components/forms/UserForm';
<UserForm
user={user}
onSubmit={handleSubmit}
isLoading={false}
/>
WorkspaceForm
import { WorkspaceForm } from '@/src/components/forms/WorkspaceForm';
<WorkspaceForm
workspace={workspace}
onSubmit={handleSubmit}
isLoading={false}
/>
Context Providers
AuthProvider
import { AuthProvider } from '@/src/components/context/AuthProvider';
<AuthProvider>
<App />
</AuthProvider>
Provides: Authentication state, user info, login/logout functions
WorkspaceProvider
import { WorkspaceProvider } from '@/src/components/context/WorkspaceProvider';
<WorkspaceProvider>
<WorkspaceContent />
</WorkspaceProvider>
Provides: Current workspace, workspace list, workspace operations
LanguageProvider
import { LanguageProvider } from '@/src/components/context/LanguageProvider';
<LanguageProvider>
<App />
</LanguageProvider>
Provides: Current language, translation function, language switcher
ThemeProvider
import { ThemeProvider } from '@/src/components/context/ThemeProvider';
<ThemeProvider>
<App />
</ThemeProvider>
Provides: Current theme, theme switcher
Creating New Components
Component Template
// src/components/[feature]/MyNewComponent.tsx
'use client';
import React from 'react';
import { Button } from '@/src/components/ui/Button';
import type { MyComponentProps } from './MyNewComponent.types';
/**
* Component description
* @param props - Component props
* @returns JSX element
*/
export function MyNewComponent({ title, onAction }: MyComponentProps) {
const [state, setState] = React.useState(false);
const handleAction = () => {
onAction?.();
setState(true);
};
return (
<div className="p-4">
<h2 className="font-bold">{title}</h2>
<Button onClick={handleAction}>Click me</Button>
</div>
);
}
Types File
// src/components/[feature]/MyNewComponent.types.ts
export interface MyComponentProps {
title: string;
onAction?: () => void;
}
Test File
// src/components/[feature]/MyNewComponent.test.tsx
import { describe, it, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { MyNewComponent } from './MyNewComponent';
describe('MyNewComponent', () => {
it('should render with title', () => {
render(<MyNewComponent title="Test" />);
expect(screen.getByText('Test')).toBeInTheDocument();
});
it('should call onAction when button clicked', async () => {
const user = userEvent.setup();
const handleAction = vi.fn();
render(<MyNewComponent title="Test" onAction={handleAction} />);
await user.click(screen.getByRole('button'));
expect(handleAction).toHaveBeenCalled();
});
});
Component Best Practices
โ Do's
- โ Keep components small and focused
- โ Extract props to TypeScript interfaces
- โ Use composition for complex components
- โ Memoize when performance matters
- โ Write tests for components
- โ Document with JSDoc comments
- โ Use semantic HTML
- โ Separate concerns (UI, logic, services)
โ Don'ts
- โ Don't make components too large (> 300 lines)
- โ Don't mix presentation and business logic
- โ Don't use inline styles
- โ Don't pass too many props (> 5)
- โ Don't use
anytypes - โ Don't hardcode strings (use i18n)
- โ Don't make API calls in render
- โ Don't forget loading/error states
Related Documentation
- ๐๏ธ ARCHITECTURE.md - Component architecture
- ๐ฃ HOOKS.md - Custom hooks
- ๐งช TESTING.md - Component testing
- ๐จ STYLING.md - Styling components
Last Updated: January 2026