# ADR-012: Frontend Component Library and Design System **Date**: 2025-12-12 **Status**: Partially Implemented ## Context The frontend is built with React, but there is no formal strategy for component reuse, styling consistency, or UI documentation. As more features are added, this can lead to a fragmented user experience, duplicated effort, and a codebase that is difficult to maintain. ## Decision We will establish a formal Design System and Component Library. This will involve using a tool like **Storybook** to develop, document, and test UI components in isolation. It will establish clear guidelines for styling, theming (e.g., dark mode), and accessibility. ## Consequences - **Positive**: Ensures a consistent and high-quality user interface. Accelerates frontend development by providing reusable, well-documented components. Improves maintainability and reduces technical debt. - **Negative**: Requires an initial investment in setting up Storybook and migrating existing components. Adds a new dependency and a new workflow for frontend development. ## Implementation Status ### What's Implemented The codebase has a solid foundation for a design system: - ✅ **Tailwind CSS v4.1.17** as the styling solution - ✅ **Dark mode** fully implemented with system preference detection - ✅ **55 custom icon components** for consistent iconography - ✅ **Component organization** with shared vs. feature-specific separation - ✅ **Accessibility patterns** with ARIA attributes and focus management ### What's Not Yet Implemented - ❌ **Storybook** is not yet installed or configured - ❌ **Formal design token documentation** (colors, typography, spacing) - ❌ **Visual regression testing** for component changes ## Implementation Details ### Component Library Structure ```text src/ ├── components/ # 30+ shared UI components │ ├── icons/ # 55 SVG icon components │ ├── Header.tsx │ ├── Footer.tsx │ ├── LoadingSpinner.tsx │ ├── ErrorDisplay.tsx │ ├── ConfirmationModal.tsx │ ├── DarkModeToggle.tsx │ ├── StatCard.tsx │ ├── PasswordInput.tsx │ └── ... ├── features/ # Feature-specific components │ ├── charts/ # PriceChart, PriceHistoryChart │ ├── flyer/ # FlyerDisplay, FlyerList, FlyerUploader │ ├── shopping/ # ShoppingListComponent, WatchedItemsList │ └── voice-assistant/ # VoiceAssistant ├── layouts/ # Page layouts │ └── MainLayout.tsx ├── pages/ # Page components │ └── admin/components/ # Admin-specific components └── providers/ # Context providers ``` ### Styling Approach **Tailwind CSS** with utility-first classes: ```typescript // Component example with consistent styling patterns ``` **Common Utility Patterns**: | Pattern | Classes | | ------- | ------- | | Card container | `bg-white dark:bg-gray-800 rounded-lg shadow-md p-6` | | Primary button | `bg-brand-primary hover:bg-brand-dark text-white rounded-lg px-4 py-2` | | Secondary button | `bg-gray-100 dark:bg-gray-700 text-gray-700 dark:text-gray-200` | | Input field | `border border-gray-300 dark:border-gray-600 rounded-md px-3 py-2` | | Focus ring | `focus:outline-none focus:ring-2 focus:ring-brand-primary` | ### Color System **Brand Colors** (Tailwind theme extensions): - `brand-primary` - Primary brand color (blue/teal) - `brand-light` - Lighter variant - `brand-dark` - Darker variant for hover states - `brand-secondary` - Secondary accent color **Semantic Colors**: - Gray scale: `gray-50` through `gray-950` - Error: `red-500`, `red-600` - Success: `green-500`, `green-600` - Warning: `yellow-500`, `orange-500` - Info: `blue-500`, `blue-600` ### Dark Mode Implementation Dark mode is fully implemented using Tailwind's `dark:` variant: ```typescript // Initialization in useAppInitialization hook const initializeDarkMode = () => { // Priority: user profile > localStorage > system preference const stored = localStorage.getItem('darkMode'); const systemPreference = window.matchMedia('(prefers-color-scheme: dark)').matches; const isDarkMode = stored ? stored === 'true' : systemPreference; document.documentElement.classList.toggle('dark', isDarkMode); return isDarkMode; }; ``` **Usage in components**: ```typescript
Content adapts to theme
``` ### Icon System **55 custom SVG icon components** in `src/components/icons/`: ```typescript // Icon component pattern interface IconProps extends React.SVGProps { title?: string; } export const CheckCircleIcon: React.FC = ({ title, ...props }) => ( {title && {title}} ); ``` **Usage**: ```typescript ``` **External icons**: Lucide React (`lucide-react` v0.555.0) used for additional icons. ### Accessibility Patterns **ARIA Attributes**: ```typescript // Modal pattern
// Button with label // Loading state
``` **Focus Management**: - Consistent focus rings: `focus:ring-2 focus:ring-brand-primary focus:ring-offset-2` - Dark mode offset: `dark:focus:ring-offset-gray-800` - No outline: `focus:outline-none` (using ring instead) ### State Management **Context Providers** (see ADR-005): | Provider | Purpose | | -------- | ------- | | `AuthProvider` | Authentication state | | `ModalProvider` | Modal open/close state | | `FlyersProvider` | Flyer data | | `MasterItemsProvider` | Grocery items | | `UserDataProvider` | User-specific data | **Provider Hierarchy** in `AppProviders.tsx`: ```typescript {children} ``` ## Key Files - `tailwind.config.js` - Tailwind CSS configuration - `src/index.css` - Tailwind CSS entry point - `src/components/` - Shared UI components - `src/components/icons/` - Icon component library (55 icons) - `src/providers/AppProviders.tsx` - Context provider composition - `src/hooks/useAppInitialization.ts` - Dark mode initialization ## Component Guidelines ### When to Create Shared Components Create a shared component in `src/components/` when: 1. Used in 3+ places across the application 2. Represents a reusable UI pattern (buttons, cards, modals) 3. Has consistent styling/behavior requirements ### Naming Conventions - **Components**: PascalCase (`LoadingSpinner.tsx`) - **Icons**: PascalCase with `Icon` suffix (`CheckCircleIcon.tsx`) - **Hooks**: camelCase with `use` prefix (`useModal.ts`) - **Contexts**: PascalCase with `Context` suffix (`AuthContext.tsx`) ### Styling Guidelines 1. Use Tailwind utility classes exclusively 2. Include dark mode variants for all colors: `bg-white dark:bg-gray-800` 3. Add focus states for interactive elements 4. Use semantic color names from the design system ## Future Enhancements (Storybook Setup) To complete ADR-012 implementation: 1. **Install Storybook**: ```bash npx storybook@latest init ``` 2. **Create stories for core components**: - Button variants - Form inputs (PasswordInput, etc.) - Modal components - Loading states - Icon showcase 3. **Add visual regression testing** with Chromatic or Percy 4. **Document design tokens** formally in Storybook 5. **Create component composition guidelines**