# Design System Philosophy Guide
## Overview
This guide explains the semantic design system philosophy for building consistent, maintainable UIs. The system is built on three core concepts: **Canvas**, **Surface**, and **Layer**.
## Core Concepts
### 1. Canvas (`bg-canvas`)
**What it is**: The application-level background that serves as the foundation for all content. The canvas is the **entire application background**, not individual pages. There is only **one canvas** in the entire application, used at the root level.
**When to use**:
- **Only at the application root** - the single root container that wraps the entire application
- The main application background (not page backgrounds)
**When NOT to use**:
- ❌ Page-level backgrounds
- ❌ Nested containers
- ❌ Cards or components
- ❌ Modals or dropdowns
- ❌ Sidebars or panels
- ❌ Anywhere else in the application
**Critical Rule**: Canvas should only appear **once** in your entire application - at the root level. All pages, routes, and components sit on top of this single canvas.
**Example**:
```tsx
// ✅ Correct: Canvas at application root (only place it should be)
// App.tsx or root layout
{/* All application content goes here */}
} />
;
// ✅ Correct: Pages use surfaces, not canvas
function Page() {
return
{/* Page content */}
;
}
// ❌ Wrong: Canvas used for a page
function Page() {
return
{/* Don't use canvas here */}
;
}
// ❌ Wrong: Canvas used for a card
{/* Card content */}
;
```
### 2. Surface (`bg-surface-1`, `bg-surface-2`, `bg-surface-3`)
**What it is**: Top-level containers that sit directly on the canvas. Surfaces never overlap each other - they are siblings in the layout hierarchy.
**When to use**:
- Main content areas
- Sections of a page
- Primary containers
- Panels that sit side-by-side
**Surface hierarchy**:
- `bg-surface-1`: Primary surface (most common)
- `bg-surface-2`: Secondary surface (for variation)
- `bg-surface-3`: Tertiary surface (rare, for special cases)
**Rules**:
- Surfaces are **siblings**, not nested (in the same plane)
- Each surface should use its corresponding layer for nested elements
- Surfaces provide the base for stacking layers
**Exception - Different Planes**:
- Modals, overlays, and popovers exist on a **different plane** (different z-index/stacking context)
- In these cases, it's acceptable to use a surface even when there's a surface below
- This is because they are visually and functionally separate from the underlying content
**Example**:
```tsx
// ✅ Correct: Surfaces as siblings
{/* Main content area */}
{/* Secondary content area - sibling, not nested */}
// ✅ Correct: Page with header and main (same surface)
{/* Header is part of the surface, not a separate surface */}
{/* Main is part of the surface, not a separate surface */}
// ❌ Wrong: Surface nested in surface (same plane)
{/* This breaks the philosophy */}
// ✅ Correct: Modal on different plane
{/* Main page content */}
Page content
{/* Modal overlay - different plane */}
{/* Modal can use surface-1 even though page uses surface-1 */}
Modal content
```
### 3. Layer (`bg-layer-1`, `bg-layer-2`, `bg-layer-3`)
**What it is**: Stacking layers that create depth within a surface. Layers stack on top of each other in a specific order.
**When to use**:
- Cards within a surface
- Group headers
- Nested containers
- Dropdowns and modals
- Sidebars
- Any element that needs to appear "on top" of a surface
**Layer hierarchy**:
- `bg-layer-1`: First layer (closest to surface)
- `bg-layer-2`: Second layer (on top of layer-1)
- `bg-layer-3`: Third layer (on top of layer-2)
**Critical Rule - Layer-to-Surface Association**:
- `bg-surface-1` → use `bg-layer-1` for nested elements
- `bg-surface-2` → use `bg-layer-2` for nested elements
- `bg-surface-3` → use `bg-layer-3` for nested elements
**Rare Exception - Visual Separation**:
In very rare cases, you may go one level above for visual separation when needed for specific UI elements:
- Inputs in modals (modal has `bg-surface-1`, input can use `bg-layer-2` for separation)
- Buttons, switches, and form controls that need more visual distinction
- **Important**: This is very rare and should only be used for interactive form elements, not for content boxes or cards
**Example**:
```tsx
// ✅ Correct: Surface-1 with layer-1
Card content
// ✅ Correct: Surface-2 with layer-2
Card content
// ❌ Wrong: Surface-1 with layer-2 (for content boxes)
{/* Wrong layer for this surface - use layer-1 for content boxes */}
// ✅ Correct: Rare exception - Input in modal for visual separation
```
## Stacking Layers
### How to Stack Layers
Layers stack in order: surface → layer-1 → layer-2 → layer-3
**Pattern**:
```
Canvas
└── Surface
└── Layer 1 (first level of depth)
└── Layer 2 (second level of depth)
└── Layer 3 (third level of depth)
```
**Example - Proper Stacking**:
```tsx
// ✅ Correct: Proper layer stacking
{/* Layer 1: Card */}
Card Title
{/* Layer 2: Nested section */}
Nested content
{/* Layer 3: Deeply nested */}
Deep content
```
**When to use each layer**:
- **Layer 1**: Most common - cards, headers, primary nested elements
- **Layer 2**: Secondary depth - nested cards, sub-sections
- **Layer 3**: Deep nesting - rarely needed, for complex hierarchies
## State Variants
### Hover States
**Critical Rule**: Hover must always match the base background layer.
**Pattern**: `bg-layer-X hover:bg-layer-X-hover`
**Examples**:
```tsx
// ✅ Correct: Matching hover
Hoverable element
Hoverable element
// ❌ Wrong: Mismatched hover
{/* Never do this */}
```
### Active States
Use `-active` variants when an element is in an active/pressed state.
```tsx
// ✅ Correct: Active state
```
### Selected States
Use `-selected` variants only when there's actual selection logic.
```tsx
// ✅ Correct: Selected state with logic
Selectable item
// ✅ Correct: With data attribute
Selectable item
```
## Common Patterns
### Pattern 1: Application Root Layout
```tsx
// ✅ Correct: Application root (only place for canvas)
// App.tsx or root layout
{/* Modal - different plane, can use surface even with surface below */}
{isModalOpen && (
Modal content
)}
);
}
```
### Pattern 4: Sidebar Layout
```tsx
// ✅ Correct: Sidebar with main content (page level, not app root)
// Both sidebar and main are siblings on the same surface
// Sidebar menu items use transparent backgrounds with hover states
function DashboardPage() {
return (
{/* Sidebar - part of the page surface */}
{/* Main content - part of the page surface */}
Main content
);
}
```
### Pattern 5: List with Items
```tsx
// ✅ Correct: List structure
List item 1
List item 2
List item 3
```
### Pattern 6: Form with Inputs
```tsx
// ✅ Correct: Form structure
// ✅ Correct: Input in modal (rare exception for visual separation)
```
## Decision Tree
### When to use Canvas?
```
Is this the root container of the entire application?
(Only one place in the whole app)
├─ YES → Use bg-canvas (application root only)
└─ NO → Continue to Surface decision
```
### When to use Surface?
```
Is this a top-level container that sits on canvas?
AND
Is it a sibling to other containers (not nested)?
OR
Is this a modal/overlay on a different plane (z-index)?
├─ YES → Use bg-surface-1 (or surface-2/3 for variation)
└─ NO → Continue to Layer decision
```
### When to use Layer?
```
Is this nested within a surface?
├─ YES → Use bg-layer-1 (or layer-2/3 for deeper nesting)
│ Match layer number to surface number
└─ NO → Re-evaluate: Should this be a surface?
```
## Text Colors
Use semantic text colors that match the hierarchy:
- `text-primary`: Main text, headings, important content
- `text-secondary`: Secondary text, descriptions
- `text-tertiary`: Tertiary text, labels, metadata
- `text-placeholder`: Placeholder text, hints
**Example**:
```tsx
```
## Common Mistakes to Avoid
### ❌ Mistake 1: Canvas for Pages or Cards
```tsx
// ❌ Wrong: Canvas used for a page
function Page() {
return
Page content
;
}
// ❌ Wrong: Canvas used for a card
Card content
;
// ✅ Correct: Pages use surfaces
function Page() {
return (
Card content
);
}
```
### ❌ Mistake 2: Nested Surfaces (Same Plane)
```tsx
// ❌ Wrong: Nested surfaces in same plane
Nested surface
// ✅ Correct: Use layer instead
Nested layer
// ✅ Correct: Exception - Modal on different plane
Page content
Modal (different plane)
```
### ❌ Mistake 3: Wrong Layer for Surface
```tsx
// ❌ Wrong: surface-1 with layer-2 (for content boxes)
Content box
// ✅ Correct: surface-1 with layer-1 (for content boxes)
Content box
// ✅ Correct: Rare exception - Input/button for visual separation
{/* Input uses layer-2 for visual separation - very rare exception */}
```
**Note**: Going one level above (e.g., `bg-layer-2` with `bg-surface-1`) is only valid in very rare cases for interactive form elements (inputs, buttons, switches) that need extra visual separation. For content boxes, cards, and normal nested elements, always match the layer number to the surface number.
### ❌ Mistake 4: Mismatched Hover
```tsx
// ❌ Wrong
```
## Best Practices
1. **Canvas is Application Root Only**: Canvas should only appear once in your entire application - at the root level (App.tsx or root layout). All pages use surfaces, not canvas.
2. **Use Surfaces for Pages and Top-Level Containers**: Surfaces are siblings, not nested (except modals/overlays on different planes)
3. **Match Layers to Surfaces**: surface-1 → layer-1, surface-2 → layer-2, etc. (Very rare exception: form elements can go one level above for visual separation)
4. **Stack Layers Properly**: Use layer-1 first, then layer-2, then layer-3 as needed
5. **Always Match Hover States**: If base is `bg-layer-X`, hover must be `hover:bg-layer-X-hover`
6. **Use Semantic Text Colors**: Match text color to importance (primary, secondary, tertiary, placeholder)
7. **Keep It Simple**: Don't over-nest. Most components only need layer-1
8. **Test Visual Hierarchy**: Ensure the stacking creates clear visual depth
## Quick Reference
### Hierarchy Structure
```
Canvas (one per page)
└── Surface 1 (top-level container)
└── Layer 1 (first level of depth)
└── Layer 2 (second level)
└── Layer 3 (third level)
```
### Common Combinations
- Application Root: `bg-canvas` (only one place in entire app)
- Single Surface Page: `bg-surface-1` → `bg-layer-1`
- Multiple Surfaces Page: Grid of `bg-surface-1` (or `bg-surface-2`) as siblings
- Card: `bg-surface-1` → `bg-layer-1 hover:bg-layer-1-hover`
- Nested Card: `bg-surface-1` → `bg-layer-1` → `bg-layer-2`
- Sidebar Layout: `bg-surface-1` (sidebar) + `bg-surface-1` (main) - both siblings
- Sidebar Menu Items: Transparent background with `hover:bg-layer-1-hover` (no base `bg-layer-1`)
### State Variants
- Hover: `bg-layer-X hover:bg-layer-X-hover`
- Active: `bg-layer-X-active` (when pressed/active)
- Selected: `bg-layer-X-selected` (when selected)
## Alignment Checklist
When reviewing components, ensure:
- [ ] Canvas is only used at the application root (one place in entire app)
- [ ] Pages use surfaces, not canvas
- [ ] Surfaces are siblings, not nested (except modals/overlays on different planes)
- [ ] Layers match their surface (surface-1 → layer-1) - except rare cases for form elements
- [ ] Sidebar menu items use transparent backgrounds with hover states
- [ ] Hover states match base layers
- [ ] Layers stack properly (1 → 2 → 3)
- [ ] Text colors are semantic (primary, secondary, tertiary, placeholder)
- [ ] Borders use semantic colors (subtle, strong)
- [ ] No unnecessary nesting
- [ ] Visual hierarchy is clear
- [ ] State variants are used correctly
- [ ] Modals/overlays use surfaces (exception to nesting rule)