Composition
One focused chapter from the Thorbis interface research. 8 rules. Read the research index for every chapter and focused study.
Composition
- Don’t proliferate boolean props.
isThread,isEditing,isInvoiceeach double the state space and hide impossible combinations. BuildJobNoteComposer,DispatchThreadComposer, andEditInvoiceComposerinstead. Share internals; never share one monolithic parent. - Compound components over render props. Export
Composer.Provider,Frame,Input,Footer,Submit. Each piece reads shared state from context. Callers compose exactly the chrome they need, noshowAttachmentsflags, norenderFootercallbacks for static structure. - Name the variant.
<ThreadComposer jobId="…" />documents itself.<Composer isThread channelId="…" showFormatting={false} />does not. Each variant is explicit about its provider, its pieces, and its actions. - Prefer children for structure. Use
childrento compose layout. Reach for a render prop only when the parent must pass data back, a list’srenderItem, not a composer’s header. - Lift state into a provider. A Forward / Peek / Dialog action that lives outside the composer frame still needs submit and the draft. Put state in a provider. Visual nesting is not the seam, the provider boundary is.
- Context is a contract: state, actions, meta. Any provider that implements the same interface can drive the same UI. Local
useStatefor an ephemeral forward. Synced store for a live job thread. The input does not know which. - UI does not know how state is stored. The provider is the only module that imports Zustand, a server sync, or
useState. Pieces consume the context interface. Swap the provider, keep the pieces. - React 19: ref is a prop, use() is context. Do not wrap with
forwardRef. Read context withuse(), which may be called conditionally. Skip this if a surface is still on React 18.
I built this for the dispatcher at 7 a.m., the tech in a crawlspace, and the owner closing the books. Quiet chrome. Precise work. I’m still learning. These are the notes.
Applied bookmark research
Reviewed 2026-09-06. These examples reinforce the existing owners; they do not introduce another visual style or claim the product behavior is implemented. Read the 26-source review and access limits.
Make invalid combinations difficult to express
Independent loading, success, and error flags can contradict each other; presentation and business logic become tangled as a component grows.
Choose an explicit state model and a semantic composition API. Reuse the approved primitives, keep domain operations outside them, and locate loading boundaries according to the work they protect. Documentation names which variants actually ship.
Thorbis example. A payment dialog composes an approved trigger, content, fields, and actions around a domain-owned operation. The button receives one coherent request state, not several competing booleans and a private set of colors.
Verify. Exercise each valid state and transition, keyboard and focus behavior, controlled and uncontrolled contracts where supported, server-rendered output, and slow or missing data. Check provenance and license before source adoption.
Do not import. No arbitrary color escape hatch, duplicate component kit, unregistered dependency, or migration from Astro merely because a source uses RSC.
Open the composition skill · Evidence: React handbook; components.build; Component Architecture for React Server Components; shadcncraft