v0.1.6·Reference
Design Guidelines Reference
Complete guide for component selection and composition decisions

Design Guidelines Reference

Complete reference for UI Lab design guidelines. These guidelines help both human developers and AI systems make consistent, beautiful component choices.

Core Principles

1. Beautiful by Default

Every component is beautiful without customization. This means:

  • No Tweaking Required – Components work beautifully out of the box
  • Consistent Visuals – All components follow the same design language
  • Dark/Light Support – Both modes are equally refined
  • Responsive – Scales from mobile to desktop gracefully

Implication for AI: Use components as-is. Don't add unnecessary styling or customization.

2. Semantic Over Visual

Component variants have semantic meaning, not just visual differences:

Button variants:
- "primary"   → Recommended action
- "secondary" → Alternative action
- "outline"   → Secondary with less emphasis
- "ghost"     → Tertiary action

Implication for AI: Choose variants based on semantic meaning, not appearance.

3. Composition Over Configuration

Complex UIs are built by composing simple components, not configuring complex ones:

// Good: Composition
<Form>
  <FormField>
    <Label>Name</Label>
    <Input />
  </FormField>
  <Button variant="primary">Submit</Button>
</Form>

// Avoid: Over-configuration
<ComplexFormBuilder fields={[...]} onSubmit={...} />

Implication for AI: Combine simple components rather than using complex mega-components.

4. Accessibility as Foundation

Accessibility is not optional—it's built into every component:

  • Keyboard Support – All interactive elements work with keyboard
  • Screen Readers – All components are properly labeled
  • Focus Management – Clear focus indicators everywhere
  • WCAG AA – All components meet WCAG AA standards

Implication for AI: Generated code includes accessibility by default, no need to add it.

Component Selection Guide

| Need | Component | Reason | |------|-----------|--------| | User performs an action | Button | Changes state, triggers logic | | Navigate to a page | Link | Navigates within app/web | | Navigate + open in new tab | Link | Supports Ctrl+Click | | Submit form | Button | Semantically correct for forms |

Examples:

// ✅ Use Button
<Button variant="primary" onClick={handleSave}>Save</Button>
<Button variant="secondary" onClick={handleDelete}>Delete</Button>

// ✅ Use Link
<Link href="/about">About Us</Link>
<Link href="/contact">Contact</Link>

// ❌ Don't do this
<Button onClick={() => navigate('/about')}>About</Button>
<Link href="#" onClick={handleSave}>Save</Link>

When to Use: Input vs. TextArea

| Need | Component | Reason | |------|-----------|--------| | Single line of text | Input | Designed for single lines | | Multiple lines of text | TextArea | Designed for multi-line content | | Email/phone/number | Input | Type attribute handles validation | | Long-form text | TextArea | Expandable, comfortable for typing |

Examples:

// ✅ Use Input
<Input type="email" placeholder="your@email.com" />
<Input type="text" placeholder="Your name" />
<Input type="number" placeholder="Age" />

// ✅ Use TextArea
<TextArea placeholder="Enter your message..." rows={5} />
<TextArea placeholder="Long-form feedback..." />

// ❌ Don't do this
<TextArea for single-line input />
<Input for multi-line text />

When to Use: Tabs vs. Menu

| Need | Component | Reason | |------|-----------|--------| | Switch between views | Tabs | Horizontal, all options visible | | Dropdown options | Menu | Vertical, collapsed by default | | Many options | Menu | Better for long lists | | Few primary sections | Tabs | Better for 2-5 sections |

Examples:

// ✅ Use Tabs
<Tabs>
  <Tab label="Overview" />
  <Tab label="Details" />
  <Tab label="Settings" />
</Tabs>

// ✅ Use Menu
<Menu>
  <MenuItem>Profile</MenuItem>
  <MenuItem>Settings</MenuItem>
  <MenuItem>Help</MenuItem>
  <MenuItem>Sign Out</MenuItem>
</Menu>

// ❌ Don't do this
<Menu for main navigation sections />
<Tabs for 10+ options />

When to Use: Modal vs. Popover

| Need | Component | Reason | |------|-----------|--------| | Require immediate response | Modal | Blocks background interaction | | Confirm critical action | Modal | Forces user decision | | Quick info/context | Popover | Non-blocking, can dismiss | | Positioning matters | Popover | Anchors to trigger element |

Examples:

// ✅ Use Modal
<Modal title="Confirm Delete">
  <p>Are you sure? This cannot be undone.</p>
  <Button variant="secondary" onClick={handleCancel}>Cancel</Button>
  <Button variant="primary">Delete</Button>
</Modal>

// ✅ Use Popover
<Popover trigger={<Button>Help</Button>}>
  <p>Click here to save your changes</p>
</Popover>

// ❌ Don't do this
<Popover for critical confirmations />
<Modal for quick tooltips />

When to Use: Toast vs. Tooltip

| Need | Component | Reason | |------|-----------|--------| | Notification (non-critical) | Toast | Visible, dismissible | | Brief hover help | Tooltip | Appears on hover, disappears | | Background operation feedback | Toast | Persists while user works | | Dense UI explanation | Tooltip | Hidden until hover |

Examples:

// ✅ Use Toast
showToast('Settings saved successfully', 'success')
showToast('Error uploading file', 'error')

// ✅ Use Tooltip
<Button>
  Help
  <Tooltip>Click for documentation</Tooltip>
</Button>

// ❌ Don't do this
<Toast for on-hover help />
<Tooltip for operation feedback />

Variant Selection Guide

Button Variants

Primary (Default)

  • Use when: User should strongly consider this action
  • Examples: "Save", "Submit", "Continue", "Complete"
  • Appearance: Most prominent, full color
<Button variant="primary">Save Changes</Button>

Secondary

  • Use when: Alternative action of similar importance
  • Examples: "Cancel", "Go Back", "Try Again"
  • Appearance: Less prominent than primary
<Button variant="secondary">Cancel</Button>

Outline

  • Use when: Multiple secondary actions needed
  • Examples: "Edit", "Download", "Share"
  • Appearance: Outlined, less emphasis
<Button variant="outline">Download</Button>

Ghost

  • Use when: Tertiary or subtle action
  • Examples: "Help", "More Options", "Close"
  • Appearance: Minimal, text-only appearance
<Button variant="ghost">Help</Button>

Form Field States

Default

  • Normal, ready for input
  • Placeholder visible
  • No error shown
<Input placeholder="Enter your email" />

Focused

  • User is interacting
  • Focus ring visible
  • Placeholder may disappear
<Input autoFocus placeholder="Enter your email" />

Filled

  • User has entered data
  • Placeholder gone
  • Value visible
<Input value="user@example.com" />

Disabled

  • User cannot interact
  • Typically appears grayed out
  • Screen reader announces disabled
<Input disabled placeholder="Not available" />

Error

  • Validation failed
  • Error message displayed
  • Visual indicator (usually red)
<Input
  error
  aria-invalid="true"
  aria-describedby="email-error"
/>
<div id="email-error">Invalid email format</div>

Composition Patterns

Form Pattern

Standard form structure:

<Form onSubmit={handleSubmit}>
  <FormField>
    <Label htmlFor="email">Email</Label>
    <Input
      id="email"
      type="email"
      value={email}
      onChange={(e) => setEmail(e.target.value)}
    />
    {errors.email && <Error>{errors.email}</Error>}
  </FormField>

  <FormField>
    <Label htmlFor="message">Message</Label>
    <TextArea
      id="message"
      value={message}
      onChange={(e) => setMessage(e.target.value)}
    />
    {errors.message && <Error>{errors.message}</Error>}
  </FormField>

  <Button variant="primary" type="submit">
    Send
  </Button>
</Form>

Key Points:

  • Every input has a Label
  • Each FormField contains one input + related elements
  • Errors displayed below the field
  • Primary button for main action

Card Pattern

Group related content:

<Card>
  <Card.Header>
    <h2>Profile</h2>
  </Card.Header>

  <Card.Body>
    <p>User information goes here</p>
  </Card.Body>

  <Card.Footer>
    <Button variant="primary">Edit</Button>
    <Button variant="secondary">Cancel</Button>
  </Card.Footer>
</Card>

Key Points:

  • Header for title/summary
  • Body for main content
  • Footer for actions
  • Provides visual grouping

Button Group Pattern

Group related actions:

<Group>
  <Button variant="primary">Save</Button>
  <Button variant="secondary">Cancel</Button>
  <Button variant="ghost">Help</Button>
</Group>

Key Points:

  • Related buttons grouped together
  • Appropriate spacing
  • Visual distinction between variants
  • Consistent sizing

Confirm important actions:

<Modal isOpen={isOpen} onClose={handleClose}>
  <Modal.Header>
    <h2>Delete Account</h2>
  </Modal.Header>

  <Modal.Body>
    <p>
      Are you sure? This action cannot be undone.
    </p>
  </Modal.Body>

  <Modal.Footer>
    <Button variant="secondary" onClick={handleClose}>
      Cancel
    </Button>
    <Button variant="primary" onClick={handleDelete}>
      Delete
    </Button>
  </Modal.Footer>
</Modal>

Key Points:

  • Clear title explaining the decision
  • Simple, direct message
  • Cancel button on left (secondary)
  • Destructive action on right (primary)
  • Modal blocks background interaction

List Pattern

Display multiple items:

<div className="space-y-md">
  {items.map((item) => (
    <Card key={item.id}>
      <div className="flex justify-between items-start">
        <div>
          <h3>{item.title}</h3>
          <p>{item.description}</p>
        </div>
        <Button variant="ghost" onClick={() => handleEdit(item)}>
          Edit
        </Button>
      </div>
    </Card>
  ))}
</div>

Key Points:

  • Consistent card structure for each item
  • Consistent spacing between items
  • Action buttons on the right
  • Appropriate hover/focus states

Responsive Design Guidelines

Mobile-First Approach

Design for mobile first, then enhance for larger screens:

// Mobile: 1 column
// Tablet: 2 columns
// Desktop: 3 columns
<Grid columns={{ base: 1, sm: 2, md: 3 }}>
  {items.map(item => <Card key={item.id}>{item}</Card>)}
</Grid>

Breakpoints

| Name | Width | Use | |------|-------|-----| | base | 0px | Mobile | | sm | 640px | Small tablet | | md | 768px | Tablet | | lg | 1024px | Desktop | | xl | 1280px | Large desktop |

Typography Scaling

Text automatically scales based on viewport:

// Heading automatically scales
<h1>Title</h1>  // 24px on mobile, 32px on desktop

// Using explicit sizes
<p className="text-sm">Small text</p>    // 12px-14px
<p className="text-base">Normal text</p>  // 14px-16px
<p className="text-lg">Large text</p>    // 16px-20px
<p className="text-xl">Heading text</p>  // 20px-28px

Spacing Scaling

Spacing automatically adjusts to viewport:

<div className="p-md gap-md">
  {/* Padding: 1rem on mobile, adjusts on larger screens */}
  {/* Gap: 1rem on mobile, adjusts on larger screens */}
</div>

Color & Theming Guidelines

Color Tokens

Always use semantic color tokens, never hardcode colors:

// ✅ Good: Use semantic tokens
<div className="bg-accent-600 text-accent-50">
  Themed content
</div>

// ✅ Good: Use semantic class names
<div className="bg-background text-foreground">
  Themed content
</div>

// ❌ Avoid: Hardcoded colors
<div style={{ backgroundColor: '#3B82F6', color: '#FFFFFF' }}>
  Hard-coded content
</div>

Token Categories

Background & Foreground

--background-50 to --background-950    // Page backgrounds
--foreground-50 to --foreground-950    // Text colors

Semantic Colors

--accent-50 to --accent-950            // Primary brand color
--success-50 to --success-950          // Success states (green)
--danger-50 to --danger-950            // Error states (red)
--warning-50 to --warning-950          // Warning states (amber)
--info-50 to --info-950                // Info states (blue)

Dark Mode

Components automatically support dark mode. Don't add special dark mode logic:

// ✅ Good: Works in both light and dark automatically
<Card>
  <h2>Content</h2>
  <p>This looks good in light and dark modes</p>
</Card>

// ❌ Avoid: Manual dark mode handling
<div className="bg-white dark:bg-black text-black dark:text-white">
  Manual theming
</div>

Accessibility Guidelines

For AI Code Generation

Every generated component must include:

  1. Semantic HTML

    // ✅ Good
    <button onClick={handleClick}>Save</button>
    
    // ❌ Avoid
    <div onClick={handleClick}>Save</div>
    
  2. ARIA Labels

    // ✅ Good: Icon buttons need labels
    <Button aria-label="Close" variant="ghost">×</Button>
    
    // ❌ Avoid: Unlabeled icon button
    <Button variant="ghost">×</Button>
    
  3. Form Labels

    // ✅ Good: Every input has a label
    <FormField>
      <Label htmlFor="email">Email</Label>
      <Input id="email" />
    </FormField>
    
    // ❌ Avoid: Input without label
    <Input placeholder="Email" />
    
  4. Error Associations

    // ✅ Good: Error is associated with input
    <Input
      aria-invalid={!!error}
      aria-describedby={error ? 'error-msg' : undefined}
    />
    {error && <div id="error-msg">{error}</div>}
    
    // ❌ Avoid: Error not associated
    <Input />
    <div>{error}</div>
    
  5. Keyboard Support

    // ✅ Good: All interactive elements are keyboard accessible
    <Button onClick={handleDelete}>Delete</Button>
    
    // ❌ Avoid: Non-interactive elements
    <div onClick={handleDelete}>Delete</div>
    
  6. Focus Management

    // ✅ Good: Modal traps focus
    <Modal isOpen={isOpen}>
      <Input autoFocus />
      <Button>Action</Button>
    </Modal>
    
    // ❌ Avoid: No focus management
    <Modal isOpen={isOpen} autoFocus={false}>
      ...
    </Modal>
    

Performance Guidelines

Use Flex and Grid Over DIVs

// ✅ Good: Use Flex for layout
<Flex direction="column" gap="md">
  <div>Item 1</div>
  <div>Item 2</div>
</Flex>

// ❌ Avoid: DIVs with inline styles
<div style={{ display: 'flex', flexDirection: 'column', gap: '1rem' }}>
  <div>Item 1</div>
  <div>Item 2</div>
</div>

Lazy Load Heavy Components

// ✅ Good: Lazy load modal
const [isOpen, setIsOpen] = useState(false)
{isOpen && <Modal>...</Modal>}

// ❌ Avoid: Always render large components
<Modal isOpen={false} style={{ display: 'none' }} />

Use Container Queries

// ✅ Good: Respond to container size
<div className="container-query">
  <Grid columns={{ base: 1, md: 2 }} />
</div>

Common Mistakes to Avoid

❌ Overusing Customization

// Bad: Too much custom styling
<Button
  style={{
    padding: '20px',
    backgroundColor: '#3B82F6',
    borderRadius: '8px',
    fontSize: '16px'
  }}
>
  Save
</Button>

// Good: Use variants and class names
<Button variant="primary" className="px-lg">
  Save
</Button>

❌ Nesting Components Wrong

// Bad: Input inside Button
<Button>
  <Input type="text" />
</Button>

// Good: Input and Button side by side
<Group>
  <Input type="text" />
  <Button>Search</Button>
</Group>

❌ Missing ARIA Labels

// Bad: Icon button without label
<Button variant="ghost">🔍</Button>

// Good: Icon button with label
<Button variant="ghost" aria-label="Search">
  🔍
</Button>

❌ Hardcoding Values

// Bad: Hardcoded spacing
<div style={{ marginBottom: '16px' }}>Item</div>

// Good: Use spacing tokens
<div className="mb-md">Item</div>

❌ Ignoring Dark Mode

// Bad: Only light mode colors
<div style={{ color: '#000000', backgroundColor: '#FFFFFF' }}>
  Content
</div>

// Good: Uses theme automatically
<div className="text-foreground bg-background">
  Content
</div>

Next Steps


These guidelines ensure beautiful, consistent, accessible UIs whether generated by humans or AI.

© 2025 UI Lab • Built for humans and machines