Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Apply React composition patterns to build flexible, maintainable components without boolean prop sprawl
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
rules/architecture-compound-components.md
1---2title: Use Compound Components3impact: HIGH4impactDescription: enables flexible composition without prop drilling5tags: composition, compound-components, architecture6---78## Use Compound Components910Structure complex components as compound components with a shared context. Each11subcomponent accesses shared state via context, not props. Consumers compose the12pieces they need.1314**Incorrect (monolithic component with render props):**1516```tsx17function Composer({18renderHeader,19renderFooter,20renderActions,21showAttachments,22showFormatting,23showEmojis,24}: Props) {25return (26<form>27{renderHeader?.()}28<Input />29{showAttachments && <Attachments />}30{renderFooter ? (31renderFooter()32) : (33<Footer>34{showFormatting && <Formatting />}35{showEmojis && <Emojis />}36{renderActions?.()}37</Footer>38)}39</form>40)41}42```4344**Correct (compound components with shared context):**4546```tsx47const ComposerContext = createContext<ComposerContextValue | null>(null)4849function ComposerProvider({ children, state, actions, meta }: ProviderProps) {50return (51<ComposerContext value={{ state, actions, meta }}>52{children}53</ComposerContext>54)55}5657function ComposerFrame({ children }: { children: React.ReactNode }) {58return <form>{children}</form>59}6061function ComposerInput() {62const {63state,64actions: { update },65meta: { inputRef },66} = use(ComposerContext)67return (68<TextInput69ref={inputRef}70value={state.input}71onChangeText={(text) => update((s) => ({ ...s, input: text }))}72/>73)74}7576function ComposerSubmit() {77const {78actions: { submit },79} = use(ComposerContext)80return <Button onPress={submit}>Send</Button>81}8283// Export as compound component84const Composer = {85Provider: ComposerProvider,86Frame: ComposerFrame,87Input: ComposerInput,88Submit: ComposerSubmit,89Header: ComposerHeader,90Footer: ComposerFooter,91Attachments: ComposerAttachments,92Formatting: ComposerFormatting,93Emojis: ComposerEmojis,94}95```9697**Usage:**9899```tsx100<Composer.Provider state={state} actions={actions} meta={meta}>101<Composer.Frame>102<Composer.Header />103<Composer.Input />104<Composer.Footer>105<Composer.Formatting />106<Composer.Submit />107</Composer.Footer>108</Composer.Frame>109</Composer.Provider>110```111112Consumers explicitly compose exactly what they need. No hidden conditionals. And the state, actions and meta are dependency-injected by a parent provider, allowing multiple usages of the same component structure.113