Our project follows a feature-based organization pattern:
src/├── components/ # Shared UI components│ ├── common/ # Basic reusable components (Button, Input, etc.)│ ├── layout/ # Layout components (Header, Sidebar, Footer)│ └── features/ # Feature-specific components├── pages/ # Page-level components and route handlers├── features/ # Feature modules (business logic + components)│ ├── auth/│ ├── dashboard/│ └── user-profile/├── hooks/ # Custom React hooks├── services/ # API clients and external service integrations├── stores/ # State management (stores, actions, reducers)├── utils/ # Utility functions and helpers├── types/ # TypeScript type definitions├── styles/ # Global styles and theme configuration└── config/ # App configuration and constants
Feature folders contain everything related to that feature: components, hooks, types, and logic. This promotes cohesion and makes features easier to maintain or remove.
Create flexible, composable components that work together while sharing implicit state.
// Example: Tabs compound componentinterface TabsContextValue { activeTab: string; setActiveTab: (tab: string) => void;}const TabsContext = createContext<TabsContextValue | null>(null);export function Tabs({ children, defaultTab }: { children: ReactNode; defaultTab: string }) { const [activeTab, setActiveTab] = useState(defaultTab); return ( <TabsContext.Provider value={{ activeTab, setActiveTab }}> <div className="tabs">{children}</div> </TabsContext.Provider> );}Tabs.List = function TabsList({ children }: { children: ReactNode }) { return <div className="tabs-list">{children}</div>;};Tabs.Tab = function Tab({ value, children }: { value: string; children: ReactNode }) { const context = useContext(TabsContext); if (!context) throw new Error('Tab must be used within Tabs'); const isActive = context.activeTab === value; return ( <button className={`tab ${isActive ? 'active' : ''}`} onClick={() => context.setActiveTab(value)} > {children} </button> );};Tabs.Panel = function TabPanel({ value, children }: { value: string; children: ReactNode }) { const context = useContext(TabsContext); if (!context) throw new Error('TabPanel must be used within Tabs'); if (context.activeTab !== value) return null; return <div className="tab-panel">{children}</div>;};
Compound components provide excellent API flexibility while maintaining encapsulation. They’re ideal for complex UI patterns like tabs, accordions, and dropdowns.