# Spacing and Iconography Reference ## Spacing Systems ### 8-Point Grid System The 8-point grid is the industry standard for consistent spacing. ```css :root { /* Base spacing unit */ --space-unit: 0.25rem; /* 4px */ /* Spacing scale */ --space-0: 0; --space-px: 1px; --space-0-5: calc(var(--space-unit) * 0.5); /* 2px */ --space-1: var(--space-unit); /* 4px */ --space-1-5: calc(var(--space-unit) * 1.5); /* 6px */ --space-2: calc(var(--space-unit) * 2); /* 8px */ --space-2-5: calc(var(--space-unit) * 2.5); /* 10px */ --space-3: calc(var(--space-unit) * 3); /* 12px */ --space-3-5: calc(var(--space-unit) * 3.5); /* 14px */ --space-4: calc(var(--space-unit) * 4); /* 16px */ --space-5: calc(var(--space-unit) * 5); /* 20px */ --space-6: calc(var(--space-unit) * 6); /* 24px */ --space-7: calc(var(--space-unit) * 7); /* 28px */ --space-8: calc(var(--space-unit) * 8); /* 32px */ --space-9: calc(var(--space-unit) * 9); /* 36px */ --space-10: calc(var(--space-unit) * 10); /* 40px */ --space-11: calc(var(--space-unit) * 11); /* 44px */ --space-12: calc(var(--space-unit) * 12); /* 48px */ --space-14: calc(var(--space-unit) * 14); /* 56px */ --space-16: calc(var(--space-unit) * 16); /* 64px */ --space-20: calc(var(--space-unit) * 20); /* 80px */ --space-24: calc(var(--space-unit) * 24); /* 96px */ --space-28: calc(var(--space-unit) * 28); /* 112px */ --space-32: calc(var(--space-unit) * 32); /* 128px */ } ``` ### Semantic Spacing Tokens ```css :root { /* Component-level spacing */ --spacing-xs: var(--space-1); /* 4px - tight spacing */ --spacing-sm: var(--space-2); /* 8px - compact spacing */ --spacing-md: var(--space-4); /* 16px - default spacing */ --spacing-lg: var(--space-6); /* 24px - comfortable spacing */ --spacing-xl: var(--space-8); /* 32px - loose spacing */ --spacing-2xl: var(--space-12); /* 48px - generous spacing */ --spacing-3xl: var(--space-16); /* 64px - section spacing */ /* Specific use cases */ --spacing-inline: var(--space-2); /* Between inline elements */ --spacing-stack: var(--space-4); /* Between stacked elements */ --spacing-inset: var(--space-4); /* Padding inside containers */ --spacing-section: var(--space-16); /* Between major sections */ --spacing-page: var(--space-24); /* Page margins */ } ``` ### Spacing Utility Functions ```tsx // Tailwind-like spacing scale generator function createSpacingScale(baseUnit: number = 4): Record { const scale: Record = { "0": "0", px: "1px", }; const multipliers = [ 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 72, 80, 96, ]; for (const m of multipliers) { const key = m % 1 === 0 ? String(m) : String(m).replace(".", "-"); scale[key] = `${baseUnit * m}px`; } return scale; } ``` ## Layout Spacing Patterns ### Container Queries for Spacing ```css /* Responsive spacing based on container size */ .card { container-type: inline-size; padding: var(--space-4); } @container (min-width: 400px) { .card { padding: var(--space-6); } } @container (min-width: 600px) { .card { padding: var(--space-8); } } ``` ### Negative Space Patterns ```css /* Asymmetric spacing for visual hierarchy */ .hero-section { padding-top: var(--space-24); padding-bottom: var(--space-16); } /* Content breathing room */ .prose > * + * { margin-top: var(--space-4); } .prose > h2 + * { margin-top: var(--space-2); } .prose > * + h2 { margin-top: var(--space-8); } ``` ## Icon Systems ### Icon Size Scale ```css :root { /* Icon sizes aligned to spacing grid */ --icon-xs: 12px; /* Inline decorators */ --icon-sm: 16px; /* Small UI elements */ --icon-md: 20px; /* Default size */ --icon-lg: 24px; /* Emphasis */ --icon-xl: 32px; /* Large displays */ --icon-2xl: 48px; /* Hero icons */ /* Touch target sizes */ --touch-target-min: 44px; /* WCAG minimum */ --touch-target-comfortable: 48px; } ``` ### SVG Icon Component ```tsx import { forwardRef, type SVGProps } from "react"; interface IconProps extends SVGProps { name: string; size?: "xs" | "sm" | "md" | "lg" | "xl" | "2xl"; label?: string; } const sizeMap = { xs: 12, sm: 16, md: 20, lg: 24, xl: 32, "2xl": 48, }; export const Icon = forwardRef( ({ name, size = "md", label, className, ...props }, ref) => { const pixelSize = sizeMap[size]; return ( ); }, ); Icon.displayName = "Icon"; ``` ### Icon Button Patterns ```tsx interface IconButtonProps extends React.ButtonHTMLAttributes { icon: string; label: string; size?: "sm" | "md" | "lg"; variant?: "solid" | "ghost" | "outline"; } const sizeClasses = { sm: "p-1.5" /* 32px total with 16px icon */, md: "p-2" /* 40px total with 20px icon */, lg: "p-2.5" /* 48px total with 24px icon */, }; const iconSizes = { sm: "sm" as const, md: "md" as const, lg: "lg" as const, }; export function IconButton({ icon, label, size = "md", variant = "ghost", className, ...props }: IconButtonProps) { return ( ); } ``` ### Icon Sprite Generation ```tsx // Build script for SVG sprite import { readdir, readFile, writeFile } from "fs/promises"; import { optimize } from "svgo"; async function buildIconSprite(iconDir: string, outputPath: string) { const files = await readdir(iconDir); const svgFiles = files.filter((f) => f.endsWith(".svg")); const symbols = await Promise.all( svgFiles.map(async (file) => { const content = await readFile(`${iconDir}/${file}`, "utf-8"); const name = file.replace(".svg", ""); // Optimize SVG const result = optimize(content, { plugins: [ "removeDoctype", "removeXMLProcInst", "removeComments", "removeMetadata", "removeTitle", "removeDesc", "removeUselessDefs", "removeEditorsNSData", "removeEmptyAttrs", "removeHiddenElems", "removeEmptyText", "removeEmptyContainers", "convertStyleToAttrs", "convertColors", "convertPathData", "convertTransform", "removeUnknownsAndDefaults", "removeNonInheritableGroupAttrs", "removeUselessStrokeAndFill", "removeUnusedNS", "cleanupNumericValues", "cleanupListOfValues", "moveElemsAttrsToGroup", "moveGroupAttrsToElems", "collapseGroups", "mergePaths", ], }); // Extract viewBox and content const viewBoxMatch = result.data.match(/viewBox="([^"]+)"/); const viewBox = viewBoxMatch ? viewBoxMatch[1] : "0 0 24 24"; const innerContent = result.data .replace(/]*>/, "") .replace(/<\/svg>/, ""); return `${innerContent}`; }), ); const sprite = `${symbols.join("")}`; await writeFile(outputPath, sprite); console.log(`Generated sprite with ${symbols.length} icons`); } ``` ### Icon Libraries Integration ```tsx // Lucide React import { Home, Settings, User, Search } from "lucide-react"; function Navigation() { return ( ); } // Heroicons import { HomeIcon, Cog6ToothIcon } from "@heroicons/react/24/outline"; import { HomeIcon as HomeIconSolid } from "@heroicons/react/24/solid"; function ToggleIcon({ active }: { active: boolean }) { const Icon = active ? HomeIconSolid : HomeIcon; return ; } // Radix Icons import { HomeIcon, GearIcon } from "@radix-ui/react-icons"; ``` ## Sizing Systems ### Element Sizing Scale ```css :root { /* Fixed sizes */ --size-4: 1rem; /* 16px */ --size-5: 1.25rem; /* 20px */ --size-6: 1.5rem; /* 24px */ --size-8: 2rem; /* 32px */ --size-10: 2.5rem; /* 40px */ --size-12: 3rem; /* 48px */ --size-14: 3.5rem; /* 56px */ --size-16: 4rem; /* 64px */ --size-20: 5rem; /* 80px */ --size-24: 6rem; /* 96px */ --size-32: 8rem; /* 128px */ /* Component heights */ --height-input-sm: var(--size-8); /* 32px */ --height-input-md: var(--size-10); /* 40px */ --height-input-lg: var(--size-12); /* 48px */ /* Avatar sizes */ --avatar-xs: var(--size-6); /* 24px */ --avatar-sm: var(--size-8); /* 32px */ --avatar-md: var(--size-10); /* 40px */ --avatar-lg: var(--size-12); /* 48px */ --avatar-xl: var(--size-16); /* 64px */ --avatar-2xl: var(--size-24); /* 96px */ } ``` ### Aspect Ratios ```css .aspect-ratios { /* Standard ratios */ --aspect-square: 1 / 1; --aspect-video: 16 / 9; --aspect-photo: 4 / 3; --aspect-portrait: 3 / 4; --aspect-cinema: 21 / 9; --aspect-golden: 1.618 / 1; } /* Usage */ .thumbnail { aspect-ratio: var(--aspect-video); object-fit: cover; } .avatar { aspect-ratio: var(--aspect-square); border-radius: 50%; } ``` ### Border Radius Scale ```css :root { --radius-none: 0; --radius-sm: 0.125rem; /* 2px */ --radius-default: 0.25rem; /* 4px */ --radius-md: 0.375rem; /* 6px */ --radius-lg: 0.5rem; /* 8px */ --radius-xl: 0.75rem; /* 12px */ --radius-2xl: 1rem; /* 16px */ --radius-3xl: 1.5rem; /* 24px */ --radius-full: 9999px; /* Component-specific */ --radius-button: var(--radius-md); --radius-input: var(--radius-md); --radius-card: var(--radius-lg); --radius-modal: var(--radius-xl); --radius-badge: var(--radius-full); } ```