# React Component Patterns React-specific implementation details for compound components. For framework-agnostic patterns, see [SKILL.md](../SKILL.md). --- ## Context Architecture **What:** Compound components share state via React Context without prop drilling. **Why:** - Implicit state sharing between parts (Root → Trigger → Content) - Clean consumer API — no manual wiring - Nested contexts for multi-level components (Accordion → Item → Trigger) **Pattern:** - Create context with `undefined` default - Consumer hook throws if used outside provider - Root provides state, children consume **Ref:** [Base UI Dialog Source](https://github.com/mui/base-ui/tree/master/packages/react/src/dialog) --- ## Essential Hooks ### `useControlledState` **What:** Unifies controlled/uncontrolled state patterns. **Why:** Single implementation handles both modes with consistent API. **Behavior:** - If `value` provided → controlled (external state) - If only `defaultValue` → uncontrolled (internal state) - Calls `onChange` in both modes **Ref:** [Radix useControllableState](https://github.com/radix-ui/primitives/blob/main/packages/react/use-controllable-state/src/useControllableState.tsx) --- ### `useId` **What:** Generate unique IDs for ARIA relationships. **Why:** Labels, descriptions, and controls need matching IDs for accessibility. **Note:** Built into React 18+. For earlier versions, use `@reach/auto-id`. --- ### `useFocusTrap` **What:** Trap focus within a container (modal dialogs). **Why:** Modal accessibility requires focus stays within dialog until closed. **Behavior:** - Tab at last element → first element - Shift+Tab at first → last element - Returns focus to trigger on close **Ref:** [focus-trap](https://github.com/focus-trap/focus-trap) library --- ### `useRovingFocus` **What:** Arrow key navigation within groups with single Tab stop. **Why:** Standard keyboard pattern for menus, tablists, toolbars. **Behavior:** - Only focused item has `tabIndex={0}` - Others have `tabIndex={-1}` - Arrows move focus, optionally loops **Ref:** [Radix RovingFocus](https://github.com/radix-ui/primitives/tree/main/packages/react/roving-focus) --- ### `useFloating` **What:** Position floating elements relative to anchors. **Why:** Popups need collision detection, scroll tracking, arrow positioning. **Use:** Wrap `@floating-ui/react` with component-specific defaults. **Ref:** [Floating UI React](https://floating-ui.com/docs/react) --- ## Ref Patterns ### Forward Refs on All Parts **What:** Every compound component part forwards refs to its DOM element. **Why:** Consumers need DOM access for focus management, measurements, animations. **Pattern:** `forwardRef((props, ref) => ...)` --- ### `useImperativeHandle` for Actions **What:** Expose component actions through ref. **Why:** Programmatic control — `dialogRef.current.open()` **Pattern:** ```tsx interface Actions { open(): void; close(): void; } useImperativeHandle(actionsRef, () => ({ open, close })); ``` **Ref:** [React useImperativeHandle](https://react.dev/reference/react/useImperativeHandle) --- ### `useMergeRefs` / `composeRefs` **What:** Combine multiple refs pointing to same element. **Why:** Compound components often need both: - Internal ref (for positioning, focus management, measurements) - Forwarded ref (for consumer access) - Floating UI ref (for anchor positioning) **Use cases:** - Trigger needs internal ref + forwarded ref + floating anchor ref - Popup needs internal ref + forwarded ref + floating ref - Any part using `useFloating` alongside `forwardRef` **Ref:** [Floating UI useMergeRefs](https://floating-ui.com/docs/react#usemergerefs), [Radix composeRefs](https://github.com/radix-ui/primitives/blob/main/packages/react/compose-refs/src/composeRefs.tsx) --- ## Render Prop Implementation **What:** The `render` prop replaces default element with custom element or component. **Key pieces:** - Accept `ReactElement` or `(props, state) => ReactElement` - Use `cloneElement` for element form - Use `mergeProps` to combine internal + external props - **Do not** accept component references (`render={Component}`) — calling components as plain functions breaks hooks reconciliation **`mergeProps` behavior:** - Event handlers — chain (both called) - className — concatenate - style — shallow merge - Other props — override **Ref:** [Base UI useRender](https://github.com/mui/base-ui/blob/master/packages/react/src/use-render/useRender.ts) --- ## Render Delegation **What:** Replace default rendered element while preserving component behavior. **Why:** - Element polymorphism (button → link) - Integrate with existing component libraries - Conditional rendering based on internal state ### Approaches | Pattern | Library | Usage | | -------------- | ------- | --------------------------------------------------------------- | | `render` prop | Base UI | `render={}` or `render={(props, state) => ...}` | | `asChild` prop | Radix | `Link` | | `as` prop | Various | `