# Component Architecture & Project Structure > Structuring components so composition beats configuration. Frontend architecture guidance from fearchitect, written by Abas Turabli and last reviewed 2026-06-21. Source: https://fearchitect.com/topics/component-architecture Use it as reference for the task at hand. Before changing code, check this guidance against the codebase: where the code already makes a different, deliberate choice, flag the conflict instead of rewriting it. Library APIs move faster than this guide, so confirm exact signatures in the official docs linked at the end. ## Summary Good component architecture separates concerns along the right seams: behavior from markup, state from display, and shared logic from specific usage. The patterns — compound components, headless components, polymorphic `as` props, container/presentational — all serve one goal: keep each unit small enough to reason about and replaceable without ripple effects. ## Definition **Composition over configuration** means a component exposes slots and children, not a growing prop list, so callers control structure rather than encoding every variant as a prop. **Compound components** (e.g. `` creates a context and owns the value; `` reads it via React 19's `use(Ctx)` instead of `useContext`. No prop drilling; callers compose children freely. **Compound component with shared context** ```tsx import { createContext, use, useState } from "react"; interface SelectCtx { value: string; onChange: (v: string) => void; } const Ctx = createContext(null); function Select({ defaultValue = "", children, }: { defaultValue?: string; children: React.ReactNode; }) { const [value, onChange] = useState(defaultValue); return {children}; } function Option({ value, label }: { value: string; label: string }) { const ctx = use(Ctx)!; return ( ); } Select.Option = Option; export { Select }; ``` Parent holds state in context; `Select.Option` reads it via React 19's `use(Ctx)`. No prop drilling; callers compose freely. ## Type-safe polymorphic `as` prop Generic `C extends ElementType` drives prop inference. When `as="a"`, TypeScript requires `href`; when omitted, the default `"button"` applies. `Omit, "as">` prevents the `as` key from conflicting. **Type-safe polymorphic component** ```tsx import type { ComponentPropsWithoutRef, ElementType } from "react"; type ButtonProps = { as?: C; variant?: "primary" | "ghost"; } & Omit, "as">; export function Button({ as, variant = "primary", ...rest }: ButtonProps) { const Tag = as ?? "button"; return ( ); } // Usage — TypeScript enforces href only on the anchor variant: // // ``` `ComponentPropsWithoutRef` ensures `href` only appears when `as="a"`. The generic defaults to `"button"` so plain usage stays ergonomic. ## Tradeoffs **Pros** - Compound components eliminate prop explosion; callers control structure. - Headless components are independently testable and style-agnostic. - Polymorphic `as` prop covers button, anchor, and router link with full TS safety. - Feature-based folders make feature deletion a single `rm -rf` with no orphaned files. - Explicit context boundaries make data flow auditable without a global store. **Cons** - Compound components add a context per family; many families mean many contexts. - Polymorphic TS typing is verbose and trips up newer TypeScript developers. - Headless components shift all styling responsibility to every consumer. - Feature folders can duplicate code when two features share a primitive. - Context with frequent updates causes broad rerenders without careful memoization. ## Key terms - **Compound component**: A family of components sharing state via context; parent owns, children consume. - **Headless component**: A hook or renderless component owning behavior but no markup or styles. - **Polymorphic `as` prop**: A generic prop letting callers choose the rendered HTML element with correct TS types. - **Feature-based colocation**: Grouping all files for one feature together; enables atomic feature deletion. - **Container/presentational**: Pattern separating data-fetching (container) from pure rendering (presentational). ## Related topics - [React Server Components](https://fearchitect.com/topics/react-server-components.md): Server-rendered components that ship zero JS to the browser. - [Client State Management](https://fearchitect.com/topics/client-state-management.md): Decide where UI state lives; pick the right tool for the scope. - [Design Systems](https://fearchitect.com/topics/design-system.md): A shared product — tokens, components, docs, and governance — at scale. - [Microfrontends & Module Federation](https://fearchitect.com/topics/microfrontends-module-federation.md): Independently deployable frontends composed at runtime in the browser. - [Monorepos (Turborepo / Nx)](https://fearchitect.com/topics/monorepos.md): One git repo, many packages, shared tooling and task caching. - [Advanced CSS Architecture](https://fearchitect.com/topics/advanced-css-architecture.md): Native CSS features that replace methodology and JS for cascade control. ## Further reading - [React — Passing Data Deeply with Context](https://react.dev/learn/passing-data-deeply-with-context) - [React — `use` API reference](https://react.dev/reference/react/use) - [Radix UI — Composition guide](https://www.radix-ui.com/primitives/docs/guides/composition) - [React TypeScript Cheatsheet — Polymorphic components](https://react-typescript-cheatsheet.netlify.app/docs/advanced/patterns_by_usecase#polymorphic-components-eg-with-as-prop)