ADR-0060 A lower hierarchy is a lower rung, and content-switcher is tabs at one
#Context
tabs was built in the pass before this one, and section B's next row is content-switcher. ADR-0050's test is applied before building anything: read what the row says, extract whatever in it is a rule, and ask whether what remains differs from something built in layer, legal levels, interactivity or governed copy.
Read against Carbon's own usage page — carbon-design-system/carbon-website src/pages/components/content-switcher/usage.mdx, the source ADR-0052 used — the row says this:
Content switchers allow users to toggle between alternate views of similar or related content, showing only one content section at a time.
Exclusivity, disclosure, one member of a set raised above its siblings. That is tabs, built last pass, in every dimension the component tier has:
tabs | a hypothetical content-switcher | |
|---|---|---|
| Layer | Arbiter | Arbiter |
| Levels | 1–3 | 1–3 |
| Interactive | yes | yes |
| Governed copy | the set's own name | the set's own name |
#Carbon names two separators and this system has one of them already
"At a lower hierarchy." Carbon's *When not to use* is explicit: *"Content switcher is often used with tabs but at a lower hierarchy to sort related contents within that tab content."* Hierarchy is exactly what this system has a ladder for, and ADR-0027 settled what it is called: emphasis is the level. A content switcher is a tab strip at a quieter rung, which tabs already expresses and a second component would express a second time. It is the identical finding to the one ADR-0059 made about Carbon's own line-against-contained tab variants, arriving one row later at the level of the whole component.
What the panels are about. The rest of the separation is semantic: *"When navigating between distinct content areas like subpages, use tabs … two tabs wouldn't contain the same sheet of paper, so the role of tabs in the information hierarchy is to separate content."* It is a good distinction and it is a claim about what the panels contain, which no check in this system can read. The tier reads layers, levels, themes, densities, motion classes and easings, and nothing in that list can tell a subpage from a filter. Two components separated only by what their contents are about would be told apart by their names.
#And the pairing Carbon documents is unrepresentable here
This is the half that decides it rather than merely arguing it.
Carbon's stated primary use of a content switcher is inside a tab panel — sorting related content within that tab's content. In this system a tab panel is inside .wr-tabs, which declares layer arbiter, and §5 says: *"Arbiters do not nest inside Arbiters … because breaking it makes budget resolution ambiguous."*
Where that refusal actually happens is worth writing out rather than asserting, because the first draft of this record got it wrong. It is caught in two of the enforcement stack's three layers and not in the one a reader would guess, which is the same shape table-row's contract records about a density override.
*The layer filter refuses it.* TABS_ACCEPTS is ['emitter'], derived from core's nesting table rather than asserted, so TabsRejectsArbiter resolves to never. Measured: Type 'ArbiterNode' is not assignable to type 'never'.
*The props boundary does not.* TabsPanel.content is ReactNode, and that is deliberate — the contract's own note says narrowing it there would restate core's nesting table in a second place where the two could drift. Measured: a <Tabs> with an <Accordion> in its selected.content compiles clean.
*wr/nesting catches it.* The rule walks JSX ancestors and finds the <Tabs> element above the <Accordion> even though the accordion arrives inside a prop object rather than as a child. Measured, on that exact composition:
Accordion is an Arbiter nested inside the Arbiter Tabs. Arbiters resolve competing requests among their children; nesting them makes it ambiguous which one resolves. [wr/nesting]So the component's documented pairing is refused — by the layer types and by the lint, and not by the props — and its standalone use is tabs at a lower rung. Both readings arrive at the same place.
#Decision
content-switcher is removed from the roster. Nothing is built and nothing is left owed. The row enters *Not carried, with the reason* with the argument above. The roster moves 54 → 53, and the Carbon term of its summing sentence moves 40 → 39.
Where a product wants Carbon's content switcher, it writes Tabs at the rung its hierarchy deserves — which is the sentence Carbon's own page is already asking for, in this system's vocabulary.
#Rejected options
Build it, because Carbon publishes it and the roster claims Carbon's set. ADR-0021's own argument for adding text-area after the fact: *"a roster that silently omits a member is worse than one that argues for excluding it, because the omission reads as a decision nobody made."* Rejected because this is the argued exclusion that sentence asks for — the row leaves the table and enters the one below it, where a reader looking for it finds the reason. Building it would add a component identical to tabs in all four dimensions, whose separator is a rung the ladder already has.
Build it as tabs with a switcher variant. Tempting, and it would keep the roster's Carbon parity at no structural cost. Rejected because the variant axis carries the rule of the set (ADR-0028, and ADR-0059 for this component in particular: exclusive, which is a checkbox-and-radio distinction one tier up). A second member on that axis would have to name a *different* rule of the set, and a content switcher's rule is the same rule — exactly one, showing one section at a time. A variant that encodes hierarchy would be a second spelling of the level, which is what ADR-0027 exists to refuse.
Keep the row and mark it as covered by tabs. A third state in the roster's State column. Rejected on roster:check's own terms: that check asserts every row declares one of two spellings and a third is *"a failure, not a state"*. A row that is neither built nor to build is a row nothing can act on, and the exclusion table is where a decision like this already has a home.
#Consequences
Roster 53, built 30. Section B drops to seven rows to build. The identity roster:check derives holds: 6 dropped + 37 distinct Carbon slugs carried = 43, Carbon's published count.
This is the third row in three passes to collapse into something built, after ADR-0057's three lists and ADR-0058's re-filing of tile. The pattern across all three is one thing: Carbon separates components on axes this tier does not have — quantity in ADR-0057, function-per-variant in ADR-0058, hierarchy and subject matter here. Each time, what remained after removing the axis was a component that already existed. That is the adversarial sample doing the job ADR-0021 took it for, and the roster getting shorter is the sample reporting a result rather than the work falling behind.
Nothing is built, no token moves, no scene moves, no baseline moves. A record and a table row, which is ADR-0050's shape and ADR-0057's.
#Measured
- Carbon's content-switcher usage page, read on 2026-09-05: *"showing only one content section at a time"*, *"at a lower hierarchy"*, and the tabs comparison — the same source ADR-0052 used.
- The four dimensions of ADR-0050's test: identical on all four to
tabs, built in the pass before this one. - §5's nesting rule, measured in all three enforcement layers:
TabsRejectsArbiterresolves tonever(refused),TabsPanel.contentisReactNodeand compiles the composition clean (not refused, deliberately), andwr/nestingreports it by name through the prop object (refused) — *darwin-arm64, this pass*. - Roster 54 → 53; the roster's Carbon rows 40 → 39; dropped 5 → 6; the identity 6 + 37 = 43 holds.
- Built 30, unchanged.
pnpm battery— the verdict this pass is measured by.