skip to content

In a component library, what is a compound component family, and why build an accordion that way rather than as one component fed an item array?

level: middleimportance: must knowfreq 48%

answer

  1. a root and its named parts
  2. state shared implicitly
  3. the consumer writes the structure
  4. every new need is a new field
  5. uniform data still suits arrays

basics

~20 s

A compound component family is a root holding shared state plus named parts that read it implicitly. Consumers arrange the parts and write their contents, so new layouts need no new API; an item array turns every need into a field.

solid answer

~50 s

A **compound family** splits a widget into a root that owns state and named parts — for an accordion: item, header, trigger and panel — which read that state implicitly, so the consumer never wires it by hand. The consumer composes the parts like structure and writes what goes inside each. On a news publisher's explainer page, one header needs an 'Updated 10:42' label, one panel embeds a video, and the homepage needs a different heading level from the article page. With an **item array**, each of those becomes a new field, and the component drifts toward over-configuration. With a compound family, the consumer simply writes the header or panel it needs. The costs are misuse (a panel outside an item), which the library should catch in development, and more parts to document. For uniform, data-driven lists, an array-fed recipe built on the parts is still reasonable.

go deeper

for a junior

Recall that a compound family is a root plus named parts that share state, and that the consumer arranges the parts and writes their content.

for a middle

Explain why an item array grows a field for every new need, how a compound family avoids that, and what misuse the library must catch.

for a senior

Show when to offer both — compound parts as the foundation and an array-fed recipe for uniform data — and how clear development errors keep the family usable.

for a principal

Set a library-wide rule for when widgets are built as compound families, so composition is consistent across components and new needs are met without growing each component's surface.

## What a compound family is A **compound component family** is a set of components designed to be used together: a **root** that owns the widget's state, and **named parts** that read and update that state without the consumer passing it explicitly. An accordion family typically has: - **Accordion** — the root: which items are open, whether several can be open at once. - **Item** — one section, identified so the root can track it. - **Header** and **Trigger** — the heading and the control that toggles the item. - **Panel** — the content shown when the item is open. The parts find their shared state through the family's root. How a given framework delivers a value from an ancestor to its descendants is that framework's mechanics; the library-level decision is that the family shares state implicitly, so consumers compose structure instead of wiring state. ## The alternative: one component fed an array The other common API is a single component given a list: each entry has a title and some content. It is concise, and it works well — until the content stops being uniform. Consider a news publisher's explainer, "What we know so far", as an accordion on an article page: 1. One header needs an "Updated 10:42" label beside the title. 2. One panel embeds a video and a pull quote. 3. The same accordion on the homepage must use a different heading level from the article page, because the WAI-ARIA Authoring Practices accordion pattern wraps each header button in a heading whose level fits the page's structure. 4. Analytics wants to know which item was opened. With an array, each need becomes a field: a header-extra field, a panel-renderer field, a heading-level field, a per-item callback. Each field is small; together they make an **over-configured** component whose fields interact in ways nobody fully tested. With a compound family, the consumer writes the header with its label, the panel with its video, and sets the heading level on the header part. **No new API is needed**, because the consumer writes the structure. | Need | Item array | Compound family | |---|---|---| | Extra label in one header | new field on every entry | write it inside that header | | Rich panel content | a renderer field | write it inside that panel | | Heading level per page | a level field | set it on the header part | | Reorder, wrap or insert between items | usually impossible | ordinary structure | ## What compound families cost - **Invalid structure is possible.** A panel outside an item, or a trigger outside a header, has no state to read. The library should detect it and warn clearly in development. - **More to learn and document.** Four parts are more surface than one component, and every part needs examples. - **Implicit coupling.** Parts only work inside their root; that is the design, but it surprises people who try to reuse a part alone. - **Behaviour still lives in one place.** The root and parts together implement the keyboard contract — Enter and Space expand a collapsed panel, and every header is in the page's Tab sequence — so rearranging what goes inside headers and panels does not disturb it. Consumers can still break it by leaving out a trigger or nesting extra controls inside a header, which is why misuse checks matter. ## When the array is still right An array is a legitimate API when the data really is **uniform** — a frequently-asked-questions block generated from a content management system, where every entry is a question and an answer. The strong pattern is to offer both: the compound family as the foundation, and a small array-fed **recipe** built on it for the uniform case. The recipe stays simple because anything non-uniform uses the parts directly. ## Beyond one platform The same trade-off exists wherever a system ships components: native mobile libraries face the choice between a list-driven container and a container that accepts composed child views. The reasoning carries over — composition when content varies, a data-driven shortcut when it does not.

  • How should a compound component family behave when a consumer places a part outside its root?
    It should fail loudly in development with a message naming the part and the root it needs, rather than rendering silently with no state. In production it should degrade without crashing the page. Clear misuse errors are a large part of what makes compound families pleasant to use.
  • Why is a heading level a good test of whether an accordion API is flexible enough?
    The Authoring Practices accordion pattern wraps each header button in a heading whose level fits the page, so the same accordion needs different levels on different pages. An array API needs a dedicated field for it; a compound family lets the consumer set it on the header part like any other structure.
  • What does offering an array-fed recipe on top of a compound family buy a library?
    The common uniform case stays one line, such as a content-managed question-and-answer block, while every non-uniform case uses the parts directly. The recipe never needs extra fields for special cases, so it does not drift into over-configuration.

saying these in an interview costs you the question

  • Compound components require the consumer to pass open state to every part
  • An item array can handle any layout if enough fields are added
  • A compound family needs no misuse checks because its parts are self-explanatory
  • Configuration arrays are always an anti-pattern in a component library
  • Parts of a compound family should work standalone outside their root