R1.11.2assembly over propsdesign

Assembly is less ambiguous than passing props

Aliases: compound component · composition API · assemble don't configure

What it is

Assembly over props writes a component’s structure as a visible tree of children: a dialog is assembled from title, body, and action bar, each occupying a place in the markup. Passing props crushes the same structure into a flat bag: showHeader, footerActions, extra. Assembly is less ambiguous because each place on the tree is a real child component; reading the markup shows “this is the action, that is the title”. Flat props let one boolean serve several intents, so the call site has to guess what the author meant.

Ambiguity happens at the moment the interface is read, not after paint. extra={true} can mean a badge, an overflow menu, or “please hide the default block”. Written as <Card.Badge> or <Card.Overflow>, intent arrives with the node and no longer shares a single slot name.

Why it happens

A property table is an unordered map; keys have no spatial relation. Readers reconstruct “what sits next to what” from naming conventions alone. Assembly writes spatial relation back into the tree: the kinds and order of children are the structure. Compilers and editors can see that tree, so completion offers legal children rather than an ever-growing list of booleans.

Props are cheap because the call is short. The cost of short is collision: a new product needs something on the right of the title, the table already has a vague extra, so extraRight and headerAddon stack on. Each new key is a reinterpretation of the old ones. Assembly adds a child type; old calls need not relearn old keys. Structure stops being “guess the key” and becomes “is this piece on the tree”.

Where it stops holding

When the structure is one or two closed switches, props are clearer — a button’s disabled is not worth <Button.Disabled>. Motion and style hooks have no child role to assemble. Channels that only emit a property dictionary, with no component tree, cannot host assembly. When the child set grows until it mirrors page sections one-for-one, assembly has slid into shipping the page inside the library: that is a wrong boundary, not a virtue of assembly.

Applying it

  • Make “place” a child component (Dialog.Title, Dialog.Actions) and leave “value” as a prop (copy string, selected id). Express place by assembly, value by props.
  • Audit the current property table: any key two product managers would explain as two different things becomes two children; delete the key.
  • Expose only legal children in editor completion; do not put internal implementation components on the same palette.
  • How to check: black out every prop name on a real call, leaving only the markup tree. If someone who has not read the docs can point to title versus actions, assembly holds. If they must look up defaults to know whether a header will appear, structure is still buried in parameters. Write a props version and an assembly version of the same UI side by side; count the keys that need a spoken explanation — that count is the ambiguity still in stock.

Related

  • Same group: R1.11.1 Slots return the decision about content to the consumer · R1.11.3 Legal parent-child pairings need explicit constraints · R1.11.4 Context lets children adapt to the container they sit in
  • Adjacent: R1.02 Component library and variants · R1.08 Premature abstraction
  • Search terms: assembly over props · compound component · composition API

Cards in the same group

Quick Actions

Share

Share this page

ios_share

https://hci.top/en/handbook/R1.11.2