This document outlines the design rules, patterns, and guidelines for the ClawHub platform to ensure consistency, accessibility, and maintainability across all components.
ClawHub uses a strict 3-5 color palette based on the OpenClaw brand:
| Token | Light Mode | Dark Mode | Usage |
|---|---|---|---|
--accent |
#dc2626 |
#dc2626 |
Primary actions, interactive elements, emphasis |
--accent-deep |
#b91c1c |
#ef4444 |
Hover states, secondary emphasis |
--ink |
#0a0a0a |
#fafafa |
Primary text |
--ink-soft |
#525252 |
#a1a1a1 |
Secondary text, descriptions |
--surface |
#ffffff |
#121212 |
Card backgrounds, elevated surfaces |
--bg |
#fafafa |
#0a0a0a |
Page background |
- Never exceed 5 colors without explicit design approval
- Never use purple/violet prominently unless explicitly requested
- Always override text color when changing background color to ensure contrast
- Use semantic tokens (
--accent,--ink,--surface) instead of raw colors
--font-sans: "Geist", system-ui, sans-serif;
--font-mono: "Geist Mono", monospace;
--font-display: "Geist", system-ui, sans-serif;| Token | Size | Usage |
|---|---|---|
--fs-xs |
0.75rem (12px) | Labels, badges, metadata |
--fs-sm |
0.875rem (14px) | Body text, descriptions |
--fs-base |
1rem (16px) | Default body text |
--fs-md |
1.125rem (18px) | Subheadings |
--fs-lg |
1.25rem (20px) | Section titles |
--fs-xl |
1.5rem (24px) | Page headings |
- Maximum 2 font families per page
- Line height 1.4-1.6 for body text (use
leading-relaxed) - Never use decorative fonts for body text
- Minimum font size: 14px for readability
- Use
text-balanceortext-prettyfor titles
Use this hierarchy for layout decisions:
- Flexbox - Default for most layouts
- CSS Grid - Only for complex 2D layouts (cards, galleries)
- Never use floats or absolute positioning unless absolutely necessary
--space-1: 0.25rem /* 4px */ --space-2: 0.5rem /* 8px */ --space-3: 0.75rem /* 12px */
--space-4: 1rem /* 16px */ --space-5: 1.5rem /* 24px */ --space-6: 2rem /* 32px */;grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));- Automatically adjusts columns based on container width
- Prevents orphan items on partial rows
- Maintains consistent card widths
/* 3-column at desktop, 2 at tablet, 1 at mobile */
grid-template-columns: repeat(3, minmax(0, 1fr));
@media (max-width: 860px) {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
@media (max-width: 520px) {
grid-template-columns: 1fr;
}| Size | Max Width | Usage |
|---|---|---|
| Default | --page-max (1200px) |
Standard pages |
| Narrow | --page-narrow (720px) |
Reading content, forms |
| Wide | Full width | Dashboards, data tables |
.card {
padding: var(--space-4);
border: 1px solid var(--line);
border-radius: var(--r-md);
background: var(--surface);
}Rules:
- Always use
display: flex; flex-direction: column;for consistent height - Add
flex: 1to content area for equal-height cards in grids - Include hover state with
border-colorand subtlebox-shadow
| Variant | Usage |
|---|---|
primary |
Main actions (Submit, Save, Download) |
secondary |
Alternative actions |
ghost |
Tertiary actions, navigation |
destructive |
Delete, remove, dangerous actions |
Rules:
- Always include visible focus state
- Minimum touch target: 44x44px on mobile
- Include
aria-labelwhen icon-only
- Labels above inputs (not inline)
- Error states use
--status-error-fg - Focus rings use
--accentwith 0.2 opacity - Minimum input height: 40px
/* Mobile first - base styles for mobile */
@media (min-width: 520px) {
/* Small tablets, large phones */
}
@media (min-width: 640px) {
/* Tablets */
}
@media (min-width: 860px) {
/* Small desktops, landscape tablets */
}
@media (min-width: 1024px) {
/* Desktops */
}
@media (min-width: 1280px) {
/* Large desktops */
}- Mobile-first approach - Base styles target mobile
- Progressive enhancement - Add complexity as viewport increases
- Test intermediate breakpoints - Avoid jarring layout jumps
- Never hide critical content on mobile
- Normal text: Minimum 4.5:1 ratio
- Large text (18px+): Minimum 3:1 ratio
- Interactive elements: Minimum 3:1 ratio
:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
border-radius: 2px;
}- Use
sr-onlyclass for visually hidden but accessible text - Always include
alttext for images (emptyalt=""for decorative) - Use semantic HTML elements (
main,nav,article,section) - Proper heading hierarchy (h1 > h2 > h3, no skipping)
/* Respect user preference */
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}--transition-fast: 150ms;
--transition-base: 200ms;
--transition-slow: 300ms;- Use
easeorease-outfor most transitions - Use
ease-in-outfor enter/exit animations - Never use
linearexcept for continuous animations
- Subtle by default - Avoid flashy animations
- Purpose-driven - Animation should provide feedback
- Respect preferences - Support
prefers-reduced-motion - Performance - Use
transformandopacityonly
- Use Lucide icons consistently
- Standard sizes: 14px, 16px, 20px, 24px
- Include
aria-hidden="true"for decorative icons - Never use emojis as icons
- Left of labels in buttons and navigation
- Right of labels for external links or dropdowns
- Centered when used alone with
aria-label
[data-theme="dark"] {
/* Dark mode overrides */
}- Never use pure white (
#ffffff) on dark backgrounds - Reduce shadow intensity in dark mode
- Adjust image brightness if needed
- Test contrast ratios in both modes
- Use CSS custom properties for theming
- Avoid deeply nested selectors (max 3 levels)
- Use
will-changesparingly - Prefer
transformovertop/leftfor animations
- Always specify
widthandheightattributes - Use
loading="lazy"for below-fold images - Use appropriate formats (WebP with fallbacks)
- Include placeholder or skeleton states
/* Component */
.component-name {
}
/* Component modifier */
.component-name.variant {
}
/* Component child */
.component-name-child {
}
/* State */
.component-name.is-active {
}
.component-name[data-state="open"] {
}src/
components/
ui/ # Primitive components (Button, Input, Card)
layout/ # Layout components (Container, Header)
styles.css # Global styles and design tokens
lib/
theme.ts # Theme utilities
preferences.ts # User preference management
Before shipping any UI changes, verify:
- Color contrast meets WCAG AA standards
- Focus states are visible
- Layout works at all breakpoints
- Animations respect
prefers-reduced-motion - Text is readable at default browser zoom
- Interactive elements have 44px minimum touch target
- Semantic HTML is used appropriately
- Dark mode has been tested