Compound Component Behavior Definitions & Hooks #201
cjpillsbury
started this conversation in
General
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
Compound Component Behavior Pattern
Executive Summary
Compound components are coordinated families of sub-components (e.g., Slider.Root, Slider.Track, Slider.Thumb, Slider.Progress) that work together to create a single interactive control. They face two equally significant architectural challenges compared to simple Component Behavior Patterns:
NEW concern (difference in kind): State sharing and coordination across Root + sub-components. How do Track, Thumb, and Progress access shared state? This challenge doesn't exist for simple components.
AMPLIFIED concerns (difference in degree): All open questions from simple Component Behavior Patterns—code sharing, event handlers, customization, i18n—apply here but become significantly more complex. Example: A time slider may support chapters, thumbnail previews, heatmaps, cue points, and clipping UI, each adding customization points, i18n needs, event coordination, and code sharing challenges.
Note on maturity: This architecture is in early exploration. Various approaches are being evaluated (PR 197 presents one example). This document discusses coordination strategies, scaling complexity, and tradeoffs rather than prescribing implementations.
Overview: Two Major Challenges
This document builds on the Component Behavior Patterns. Compound components face two equally significant architectural challenges:
1. NEW: State Sharing and Coordination
Simple components don't need to share state—a play button is self-contained. Compound components require coordination: Thumb needs Track dimensions, Progress needs fill percentage, all parts need interaction state.
Core questions:
This is a difference in kind—a fundamentally new concern that doesn't exist for simple components.
2. AMPLIFIED: Scaling Complexity
All the open questions from Component Behavior Patterns apply to compound components but with significantly increased complexity:
Example: A time slider might start simple but could support chapters (positioning, i18n), thumbnail previews (async, rendering), heatmaps (data, performance), cue points (markers, interaction), and clipping UI (range selection, constraints). Each addition amplifies all the existing concerns and increases bundle size.
This is a difference in degree—same architectural questions, but substantially more complex to solve.
Core Concerns for Compound Components
1. State Sharing Mechanism
Challenge: Sub-components (Track, Thumb, Progress) need access to state established by Root.
Likely approach: Component-level context (React Context API, Web Component context protocol).
Open questions:
What does context provide?
What level of granularity?
Framework-specific variations: React has Context API, HTML/Web Components use context protocol (same as for media store state). Implementation details may differ, but conceptual pattern likely similar.
2. What State Gets Shared
Challenge: Determine what information sub-components actually need from Root.
Categories of shared state:
Open questions:
3. Element Reference Management
Challenge: Compound components manage multiple DOM element references (root, track, thumb, etc.).
Approaches:
_setRootElement,_setTrackElement)attach(rootEl, trackEl)Consideration: Different frameworks handle refs differently (React
useRef, Web Components lifecycle). Pattern must work across frameworks or explicitly diverge.4. Behavior Encapsulation
Challenge: Complex interaction logic (pointer drag, keyboard navigation) spans multiple components.
Where does behavior logic live?
Tradeoffs: Core classes provide encapsulation and sharing but add abstraction. Framework-specific hooks are simpler but duplicate logic. Same code sharing question as Component Props & Attributes Pattern.
Example from PR 197: One approach being explored uses core behavior classes with element setters as part of state (
_setRootElement,_setTrackElement). This eliminates imperativeattach()/detach()seams by making element references declarative. React integration uses auseCorehook that manages instance lifecycle and returns computed state via context to children.5. Focus Management & Keyboard Navigation
Challenge: Managing focus and keyboard navigation across compound component parts.
Concerns:
A11y requirements: WCAG compliance requires logical focus order, visible focus indicators, keyboard-only operation. Screen readers need clear focus announcements.
Platform implications: Smart TVs use D-pad navigation, game consoles use controllers, accessibility users rely on keyboard. Focus management isn't optional—it's critical for multiple use cases.
Open questions: Which compound parts are focusable? How to handle focus when dragging? How does focus management integrate with behavior hooks? Should this be framework-agnostic or platform-specific?
6. Collection Management
Challenge: Managing dynamic collections of items within compound components.
Examples:
Concerns:
Relevance: Essential for extensible compound components. Menus, markers, and lists are common patterns in media players.
Open questions: How do collections integrate with compound state sharing? Should items be sub-components or data? How to handle selection/active states across collections?
How Complexity Scales: Time Slider Extensions
To illustrate how compound components amplify the concerns from Component Props & Attributes Pattern, consider how a time slider might evolve:
Basic Time Slider
Components: Root, Track, Thumb, Progress
Concerns at this stage:
data-orientation)+ Chapter Markers
Adds: Render chapter markers at specific time positions on the track
Amplifies:
+ Thumbnail Previews
Adds: Show thumbnail image when hovering over track
Amplifies:
+ Heatmap Overlay
Adds: Visual representation of video engagement or important moments
Amplifies:
+ Cue Points
Adds: Custom markers at specific times (ads, key moments, etc.)
Amplifies:
+ Clipping UI
Adds: Range selection with start/end handles for creating clips
Amplifies:
Impact on Architectural Concerns
Each addition demonstrates how compound component concerns scale:
Code size: Basic slider is ~5KB. Adding chapters, thumbnails, heatmap rendering, cue points, and clipping could add 15-20KB+ of rendering logic, data handling, and interaction code. Tree-shaking and optional features become critical.
Code sharing: Basic slider logic might be shareable, but chapters, thumbnails, heatmaps involve framework-specific rendering, data handling, and performance considerations. The sharing strategy question becomes more nuanced.
Event handlers: From simple pointer drag to coordinating clicks on chapters, hovers on thumbnails, drags on multiple handles. Handler naming and organization becomes critical.
Customization: From 4 sub-components (Root/Track/Thumb/Progress) to 10+ extension points (chapters, thumbnails, heatmap, cue points, clip handles). Each needs clear customization patterns.
i18n: From "Seek" ARIA label to chapter titles, thumbnail alt text, cue point labels, clip duration formatting. Centralized i18n strategy becomes essential.
This scaling illustrates: While state sharing is new to compound components, the amplification of existing concerns (including bundle size) is equally significant and must be addressed architecturally.
Open Questions & Future Directions
Compound components raise all the questions from (simple) Component Behavior Patterns, plus coordination-specific questions:
Coordination Questions (New)
State sharing mechanism: What does context provide? Raw state, computed state, element refs, methods, or all of the above? Single context or multiple?
Element reference management: State-based setters (PR 197 approach), imperative methods, callback patterns, or framework-specific refs?
Behavior encapsulation: Core classes, framework hooks, shared utilities, or framework-specific implementations?
Lifecycle coordination: How to ensure proper setup/teardown across multiple coordinated elements?
Nesting and composition: How do compound components nest (e.g., Menu with Slider inside)? How does state sharing work across multiple levels?
Amplified Questions (Same as Simple Components, But More Complex)
Code sharing: More complex for compound components—is sharing feasible across React/HTML, or should they diverge? How do extensions (chapters, thumbnails) affect this?
Event handlers: How to coordinate handlers across multiple elements? Naming strategies for complex interactions?
Customization/Extensibility: With 10+ potential extension points, how to make customization approachable? Patterns for extending without breaking?
i18n integration: Centralized registry? Per-component overrides? How to handle scaling from few labels to many?
Code size management: Tree-shaking strategies for optional features? Bundle splitting for extensions like thumbnails/heatmaps?
Controlled vs uncontrolled: Should compound components support controlled patterns (
value/onChange)? If so, which parts are controllable? Is this necessary given components are designed to work with media store state?Connection to Component Props & Attributes Pattern
Compound components extend the behavior hook pattern with coordination concerns:
Simple components (from component-props-pattern):
Compound components (this document):
The fundamental transformation (state → semantic props) remains the same. Compound components use context to share state from Root's behavior hook to sub-components' behavior hooks.
Same questions, additional concerns: Code sharing, event handlers, i18n, customization—all apply to compound components, with the added complexity of coordinating across multiple parts.
Beta Was this translation helpful? Give feedback.
All reactions