# Spacing Philosophy
**Master the "parent controls children" spacing strategy** that eliminates 90% of layout inconsistencies. Learn when to use margin, padding, or gap—and why children should never add their own margins.
---
## Table of Contents
1. [The Golden Rules](#the-golden-rules)
2. [Parent Controls Children Strategy](#parent-controls-children-strategy)
3. [Decision Tree: Margin vs Padding vs Gap](#decision-tree-margin-vs-padding-vs-gap)
4. [Common Patterns](#common-patterns)
5. [Before/After Examples](#beforeafter-examples)
6. [Anti-Patterns to Avoid](#anti-patterns-to-avoid)
7. [Quick Reference](#quick-reference)
---
## The Golden Rules
These 5 rules eliminate 90% of spacing inconsistencies:
### Rule 1: Parent Controls Children
**Children don't add their own margins. The parent controls spacing between siblings.**
```tsx
// ✅ CORRECT - Parent controls spacing
Item 1Item 2Item 3
// ❌ WRONG - Children add margins
Item 1Item 2Item 3 {/* Inconsistent: last one has no margin */}
```
**Why this matters:**
- Eliminates "last child" edge cases
- Makes components reusable (they work in any context)
- Changes propagate from one place (parent)
- Prevents margin collapsing bugs
---
### Rule 2: Use Gap for Siblings
**For flex and grid layouts, use `gap-*` to space siblings.**
```tsx
// ✅ CORRECT - Gap for flex/grid
123
// ❌ WRONG - Children with margins
```
---
### Rule 3: Use Padding for Internal Spacing
**Padding is for spacing _inside_ a component, between the border and content.**
```tsx
// ✅ CORRECT - Padding for internal spacing
TitleContent
// ❌ WRONG - Using margin for internal spacing
Title
```
---
### Rule 4: Use space-y for Vertical Stacks
**For vertical stacks (not flex/grid), use `space-y-*` utility.**
```tsx
// ✅ CORRECT - space-y for stacks
// ❌ WRONG - Children with margins
```
**How space-y works:**
```css
/* space-y-4 applies margin-top to all children except first */
.space-y-4 > * + * {
margin-top: 1rem; /* 16px */
}
```
---
### Rule 5: Margins Only for Exceptions
**Use margin only when a specific child needs different spacing from its siblings.**
```tsx
// ✅ CORRECT - Margin for exception
Normal spacingNormal spacingExtra spacing above this oneNormal spacing
// Use case: Visually group related items
Section 1
Content
Section 2
{/* Extra margin to separate sections */}
Content
```
---
## Parent Controls Children Strategy
### The Problem with Child-Controlled Spacing
When children control their own margins:
```tsx
// ❌ ANTI-PATTERN
function TodoItem({ className }: { className?: string }) {
return
Todo
;
}
// Usage
{/* Has mb-4 */}
{/* Has mb-4 */}
{/* Has mb-4 - unwanted margin at bottom! */}
;
```
**Problems:**
1. ❌ Last item has unwanted margin
2. ❌ Can't change spacing without modifying component
3. ❌ Margin collapsing creates unpredictable spacing
4. ❌ Component not reusable in different contexts
---
### The Solution: Parent-Controlled Spacing
```tsx
// ✅ CORRECT PATTERN
function TodoItem({ className }: { className?: string }) {
return
Todo
; // No margin!
}
// Parent controls spacing
{/* No unwanted margin */}
// Different context, different spacing
// Another context, flex layout
```
**Benefits:**
1. ✅ No edge cases (last child, first child, only child)
2. ✅ Spacing controlled in one place
3. ✅ Component works in any layout context
4. ✅ No margin collapsing surprises
5. ✅ Easier to maintain and modify
---
## Decision Tree: Margin vs Padding vs Gap
Use this flowchart to choose the right spacing method:
```
┌─────────────────────────────────────────────┐
│ What are you spacing? │
└─────────────┬───────────────────────────────┘
│
┌──────┴──────┐
│ │
▼ ▼
Siblings? Inside a component?
│ │
│ └──> USE PADDING
│ className="p-4"
│
├──> Is parent using flex or grid?
│ │
│ ├─YES──> USE GAP
│ │ className="flex gap-4"
│ │ className="grid gap-6"
│ │
│ └─NO───> USE SPACE-Y or SPACE-X
│ className="space-y-4"
│ className="space-x-2"
│
└──> Exception case?
(One child needs different spacing)
│
└──> USE MARGIN
className="mt-8"
```
---
## Common Patterns
### Pattern 1: Form Fields (Vertical Stack)
```tsx
// ✅ CORRECT
```
**Spacing breakdown:**
- `space-y-4` on form: 16px between field groups
- `space-y-2` on field group: 8px between label and input
- No margins on children
---
### Pattern 2: Button Group (Horizontal Flex)
```tsx
// ✅ CORRECT
// Responsive: stack on mobile, row on desktop
```
**Why gap over space-x:**
- Works with `flex-wrap`
- Works with `flex-col` (changes direction)
- Consistent spacing in all directions
---
### Pattern 3: Card Grid
```tsx
// ✅ CORRECT
Item 1Item 2Item 3
```
**Why gap:**
- Consistent spacing between rows and columns
- Works with responsive grid changes
- No edge cases (first row, last column, etc.)
---
### Pattern 4: Card Internal Spacing
```tsx
// ✅ CORRECT
TitleDescription
Paragraph 1
Paragraph 2
```
**Spacing breakdown:**
- `p-6` on Card: 24px internal padding
- `space-y-4` on CardContent: 16px between paragraphs
- `pt-4` on CardFooter: Additional top padding for visual separation
---
### Pattern 5: Page Layout
```tsx
// ✅ CORRECT
Page Title
Section 1ContentSection 2Content
```
**Spacing breakdown:**
- `px-4`: Horizontal padding (prevents edge touching)
- `py-8`: Vertical padding (top and bottom spacing)
- `space-y-6`: 24px between sections
- No margins on children
---
## Before/After Examples
### Example 1: Button Group
#### ❌ Before (Child-Controlled)
```tsx
function ActionButton({ children, className }: Props) {
return ;
}
// Usage
CancelSaveDelete {/* Unwanted mr-4 */}
;
```
**Problems:**
- Last button has unwanted margin
- Can't change spacing without modifying component
- Hard to use in vertical layout
#### ✅ After (Parent-Controlled)
```tsx
function ActionButton({ children, className }: Props) {
return ;
}
// Usage
CancelSaveDelete
// Different context: vertical
CancelSave
```
**Benefits:**
- No edge cases
- Reusable in any layout
- Easy to change spacing
---
### Example 2: List Items
#### ❌ Before (Child-Controlled)
```tsx
function ListItem({ title, description }: Props) {
return (
{title}
{description}
);
}
{/* Unwanted mb-6 */}
;
```
**Problems:**
- Last item has unwanted bottom margin
- Can't change list spacing without modifying component
- Internal `mb-2` hard to override
#### ✅ After (Parent-Controlled)
```tsx
function ListItem({ title, description }: Props) {
return (
{title}
{description}
);
}
// Different context: compact spacing
```
**Benefits:**
- No unwanted margins
- Internal spacing controlled by `space-y-2`
- Reusable with different spacings
---
### Example 3: Form Fields
#### ❌ Before (Mixed Strategy)
```tsx
```
**Problems:**
- Spacing scattered across children
- Hard to change consistently
- Have to remember `mt-6` for button
#### ✅ After (Parent-Controlled)
```tsx
```
**Benefits:**
- Spacing controlled in 2 places: form (`space-y-4`) and field groups (`space-y-2`)
- Easy to change all field spacing at once
- Consistent and predictable
---
## Anti-Patterns to Avoid
### Anti-Pattern 1: Last Child Special Case
```tsx
// ❌ WRONG
{
items.map((item, index) => (
{item.name}
));
}
// ✅ CORRECT
{items.map((item) => (
{item.name}
))}
;
```
---
### Anti-Pattern 2: Negative Margins to Fix Spacing
```tsx
// ❌ WRONG - Using negative margin to fix unwanted spacing
{/* Canceling out previous margin */}
Content
// ✅ CORRECT - Parent controls spacing
Content
```
**Why negative margins are bad:**
- Indicates broken spacing strategy
- Hard to maintain
- Creates coupling between components
---
### Anti-Pattern 3: Mixing Gap and Child Margins
```tsx
// ❌ WRONG - Gap + child margins = unpredictable spacing
{/* gap + mr-2 = 24px */}
// ✅ CORRECT - Only gap
// ✅ CORRECT - Exception case
{/* Intentional extra space */}
```
---
### Anti-Pattern 4: Using Margins for Layout
```tsx
// ❌ WRONG - Using margins to create layout
{/* Pushing content for sidebar */}
Content
// ✅ CORRECT - Use proper layout (flex/grid)
Content
```
---
## Quick Reference
### Spacing Method Cheat Sheet
| Use Case | Method | Example |
| ----------------------- | ----------- | ------------ |
| **Flex siblings** | `gap-*` | `flex gap-4` |
| **Grid siblings** | `gap-*` | `grid gap-6` |
| **Vertical stack** | `space-y-*` | `space-y-4` |
| **Horizontal stack** | `space-x-*` | `space-x-2` |
| **Inside component** | `p-*` | `p-6` |
| **One child exception** | `m-*` | `mt-8` |
### Common Spacing Values
| Class | Pixels | Usage |
| ---------------------- | ----------- | ---------------------- |
| `gap-2` or `space-y-2` | 8px | Tight (label + input) |
| `gap-4` or `space-y-4` | 16px | Standard (form fields) |
| `gap-6` or `space-y-6` | 24px | Sections (cards) |
| `gap-8` or `space-y-8` | 32px | Large gaps |
| `p-4` | 16px | Standard padding |
| `p-6` | 24px | Card padding |
| `px-4 py-8` | 16px / 32px | Page padding |
### Decision Flowchart (Simplified)
```
Need spacing?
│
├─ Between siblings?
│ ├─ Flex/Grid parent? → gap-*
│ └─ Regular parent? → space-y-* or space-x-*
│
├─ Inside component? → p-*
│
└─ Exception case? → m-* (sparingly)
```
---
## Best Practices Summary
### Do ✅
1. **Use parent-controlled spacing** (`gap`, `space-y`, `space-x`)
2. **Use `gap-*` for flex and grid** layouts
3. **Use `space-y-*` for vertical stacks** (forms, content)
4. **Use `p-*` for internal spacing** (padding inside components)
5. **Use margin only for exceptions** (mt-8 to separate sections)
6. **Let components be context-agnostic** (no built-in margins)
### Don't ❌
1. ❌ Add margins to reusable components
2. ❌ Use last-child selectors or conditional margins
3. ❌ Mix gap with child margins
4. ❌ Use negative margins to fix spacing
5. ❌ Use margins for layout (use flex/grid)
6. ❌ Hard-code spacing in child components
---
## Spacing Checklist
Before implementing spacing, verify:
- [ ] **Parent controls children?** Using gap or space-y/x?
- [ ] **No child margins?** Components don't have mb-_ or mr-_?
- [ ] **Consistent method?** Not mixing gap + child margins?
- [ ] **Reusable components?** Work in different contexts?
- [ ] **No edge cases?** No last-child or first-child special handling?
- [ ] **Semantic spacing?** Using design system scale (4, 8, 12, 16...)?
---
## Next Steps
- **Practice**: Refactor existing components to use parent-controlled spacing
- **Explore**: [Interactive spacing examples](/dev/spacing)
- **Reference**: [Quick Reference Tables](./99-reference.md)
- **Layout Patterns**: [Layouts Guide](./03-layouts.md)
---
**Related Documentation:**
- [Layouts](./03-layouts.md) - When to use Grid vs Flex
- [Foundations](./01-foundations.md) - Spacing scale tokens
- [Component Creation](./05-component-creation.md) - Building reusable components
- [Quick Start](./00-quick-start.md) - Essential patterns
**Last Updated**: November 2, 2025