Component Architecture Patterns
Build accessible, headless UI components using proven patterns from Base UI, Radix, and Ark UI. These patterns are framework-agnostic — core concepts apply across React, Vue, Svelte, Solid, and vanilla JS.
Primary sources:
- •Base UI Handbook
- •Ark UI — Cross-framework implementation
- •Zag.js — State machines for UI components
Framework-specific: react.md | lit.md
Core Principles
- •Headless over styled — Separate behavior from presentation
- •Compound over monolithic — Small composable parts over config-heavy megacomponents
- •Controlled + uncontrolled — Support both state ownership models
- •Accessible by default — ARIA, keyboard nav, focus management built-in
- •State via attributes — Expose state through
data-*for framework-agnostic styling
Pattern 1: Compound Components
What: Components as related parts sharing state through context, each mapping 1:1 to DOM elements.
Why:
- •Declarative — assemble like building blocks, reorder/omit parts freely
- •Each part is an independent styling target
- •DOM structure maps directly to ARIA roles
Standard hierarchies:
| Type | Parts |
|---|---|
| Popups | Root → Trigger → Portal → Positioner → Popup → Arrow |
| Collections | Root → List → Trigger + Panel |
| Forms | Root → Label → Control → Description → Error |
Ref: Base UI Composition
Pattern 2: Controlled & Uncontrolled State
What: Support external state control OR internal state with consistent prop naming.
Why:
- •Flexibility for simple and complex use cases
- •Predictable API across components
- •Change details enable fine-grained control (cancel changes, track reasons)
Convention:
| State | Uncontrolled | Controlled | Handler |
|---|---|---|---|
| Open | defaultOpen | open | onOpenChange(open, details) |
| Value | defaultValue | value | onValueChange(value, details) |
| Checked | defaultChecked | checked | onCheckedChange(checked, details) |
Change details: { reason, event, cancel() }
Pattern 3: Prop Getters
What: Functions returning HTML attributes for DOM elements, abstracting logic from rendering.
Why:
- •Portable across frameworks (React, Vue, Svelte, Solid)
- •Clean separation of concerns
- •Composable via
mergeProps()
Example: getTriggerProps() returns { aria-expanded, aria-haspopup, onClick, onKeyDown }
Pattern 4: State via Data Attributes
What: Expose state through data-* attributes for CSS targeting.
Why:
- •Framework-agnostic styling
- •No JS needed for state-based styles
- •Inspectable in DevTools
Standard attributes:
- •
data-open/data-closed— Visibility - •
data-checked/data-unchecked— Toggle state - •
data-highlighted— Focus within group - •
data-disabled,data-valid,data-invalid - •
data-side,data-align— Positioning
CSS variables: --available-height, --anchor-width, --transform-origin
Ref: Base UI Styling
Pattern 5: Accessibility
What: ARIA, keyboard navigation, focus management built into architecture.
Why:
- •Accessibility is structural, not decorative
- •Users expect standard keyboard interactions
- •Consistent patterns reduce errors
Key concerns:
- •ARIA attributes — Auto-managed from state
- •Focus trapping — Modals trap focus within
- •Roving tabindex — One tabbable item, arrows navigate
- •Virtual focus —
aria-activedescendantfor long lists - •Typeahead — A-Z jumps to matches
Ref: Base UI Accessibility, WAI-ARIA Practices
For detailed accessibility patterns, load the aria skill.
Pattern 6: Floating Positioning
What: Position popups relative to triggers with collision detection.
Why: Handles viewport boundaries, scroll, resize automatically.
Config: side, align, sideOffset, collision (flip/shift), trackAnchor
Ref: Floating UI
API Conventions
| Category | Props |
|---|---|
| Interaction | disabled, required, readOnly |
| Collections | multiple, loopFocus, orientation |
| Popups | modal, closeOnEscape, closeOnOutsideClick, keepMounted |
| Positioning | side, align, sideOffset, collision |
Imperative actions: actionsRef exposing open(), close(), toggle()
See props.md for naming conventions.
Reference Files
| File | Contents |
|---|---|
| lit.md | Lit controllers, mixins, context |
| lit-fundamentals.md | ReactiveElement lifecycle, properties, styling |
| react.md | React hooks, context, refs |
| props.md | Prop naming, conventions, defaults |
| styling.md | Data attributes, CSS variables |
| animation.md | CSS transitions, JS animation libs |
| polymorphism.md | render vs asChild patterns |
| collection.md | Collections, portals, virtualization |
| anti-patterns.md | Common component mistakes |
For accessibility patterns (ARIA, keyboard, focus), load the aria skill.
Review
For structured component reviews, load the review workflow:
| File | Contents |
|---|---|
| workflow.md | Review process and severity |
| checklist.md | Component review checklist |
| templates.md | Issue and report formats |
Implementation Sources
| Resource | Use For |
|---|---|
| Base UI Source | React reference implementations |
| Radix Primitives | Alternative approach |
| Zag.js | Framework-agnostic state machines |
| Floating UI | Positioning |
Related Skills
| Need | Use |
|---|---|
| Accessibility patterns | aria skill |
| API design principles | api skill |
| Documentation patterns | docs skill |