Problem
Default-slot nesting is implemented across every surface — the CLI reads the convention, the engine captures the nesting, both transforms emit it, the render direction puts it back, and the plugin panel now declares it (#665, #668). What has actually been run is narrower than that: one CLI path, against one library, on components whose siblings happen to be distinctly named.
The behaviour is also gated in a way that is easy to misread as broken. Three independent conditions decide whether nesting happens, one of them differs between a component and a composition, and a fourth output — the defaultSlot: true marker — is deliberately ungated and appears even when nesting does not. So "I turned it on and nothing changed" is an expected outcome in several cells of the matrix, and there is currently no way to tell that apart from a defect.
Two specific gaps that make this urgent rather than tidy:
- The two switches live in different places and neither mentions the other. Naming the default slot is necessary but not sufficient for a component:
spec.defaultSlotContent must also be on. In the plugin those are two checkboxes in two different sections (Props and Examples). Nothing in either surface tells you the other exists.
- Nothing has compared the two surfaces. The parity claim — same node, same declared convention, same spec whether generated by the CLI or the plugin — is the whole point of the plugin change, and it has never been checked.
Potential solution(s)
- Walk the gate matrix below on one component and one composition, recording actual output per cell, so each "nothing changed" is either confirmed as designed or becomes a bug report.
- Compare CLI and plugin output for the same node under the same declared convention, and diff them.
- Where a cell's expected outcome is surprising on reflection, treat that as a finding about the design rather than only about the implementation — particularly the component/composition asymmetry.
Acceptance criteria
The gate matrix
Each row is a configuration; the last two columns are what the spec should contain. defaultSlot: true on the slot prop and the nesting itself are separate outputs with different gates — that separation is the thing most likely to read as a bug.
| Convention declared |
Pro |
defaultSlotContent |
Host kind |
defaultSlot: true? |
Nesting? |
| no |
— |
— |
either |
no |
no |
| yes, empty list |
— |
— |
either |
no |
no |
| yes |
no |
on |
either |
yes |
no |
| yes |
yes |
off |
component |
yes |
no |
| yes |
yes |
on |
component |
yes |
yes |
| yes |
yes |
off |
composition |
yes |
yes |
| yes |
yes |
on |
composition |
yes |
yes |
Structural preconditions
These decide whether a given slot flattens, independently of the gates above:
CLI ↔ plugin parity
Round trip
Case data
- Fixture: an action-list component and a card component for the component rows — both verified through the CLI and both carry a nested instance with a filled default slot. A composition for the composition rows; one of the canonical screens works, though its layout levels are frames rather than instances
- Workspace: eg for the CLI side and the plugin side; a test library for the structural rows that need deliberately odd frames
- Territory: testing, crossing cli / specs-from-figma / plugin-settings
- Size: m
Notes
Several structural rows need frames no design file currently contains — the hidden instance, the bound-rather-than-filled slot, the two-deep chain. #656 is the authoring work and already carries most of them; this issue is the verification that consumes them, so the two are worth sequencing together rather than merging.
What is already known, so nobody re-derives it: the engine behaviour is proven on the CLI path against a real library, where one screen's slot-content entries dropped from 20 to 3 and an action-list component's from 24 to 8. Every gate has unit coverage. What has never run is the plugin path, the render round trip, and every structural row above except the plain nested-instance case.
One known limitation that will show up while testing and is not this issue's to fix: sibling instances sharing a Figma name collapse to a single anatomy element, because anatomy and elements key by layer name. ADR-044 is the accepted answer and is unimplemented. Expect three identically-named cards to read as one, and do not file it again.
Problem
Default-slot nesting is implemented across every surface — the CLI reads the convention, the engine captures the nesting, both transforms emit it, the render direction puts it back, and the plugin panel now declares it (#665, #668). What has actually been run is narrower than that: one CLI path, against one library, on components whose siblings happen to be distinctly named.
The behaviour is also gated in a way that is easy to misread as broken. Three independent conditions decide whether nesting happens, one of them differs between a component and a composition, and a fourth output — the
defaultSlot: truemarker — is deliberately ungated and appears even when nesting does not. So "I turned it on and nothing changed" is an expected outcome in several cells of the matrix, and there is currently no way to tell that apart from a defect.Two specific gaps that make this urgent rather than tidy:
spec.defaultSlotContentmust also be on. In the plugin those are two checkboxes in two different sections (Props and Examples). Nothing in either surface tells you the other exists.Potential solution(s)
Acceptance criteria
The gate matrix
Each row is a configuration; the last two columns are what the spec should contain.
defaultSlot: trueon the slot prop and the nesting itself are separate outputs with different gates — that separation is the thing most likely to read as a bug.defaultSlotContentdefaultSlot: true?defaultSlotContent, because composed content is the reason it existsStructural preconditions
These decide whether a given slot flattens, independently of the gates above:
slotContentExamplesentry pointed at from the binding. The host declares that slot, so content in it is the slot's authored default$nestedpath on the outer oneCLI ↔ plugin parity
specs generateand through the pluginmetadata.conventions.platforms.figma.slotsis present in both, so the render direction can resolve the slot either wayRound trip
Case data
Notes
Several structural rows need frames no design file currently contains — the hidden instance, the bound-rather-than-filled slot, the two-deep chain. #656 is the authoring work and already carries most of them; this issue is the verification that consumes them, so the two are worth sequencing together rather than merging.
What is already known, so nobody re-derives it: the engine behaviour is proven on the CLI path against a real library, where one screen's slot-content entries dropped from 20 to 3 and an action-list component's from 24 to 8. Every gate has unit coverage. What has never run is the plugin path, the render round trip, and every structural row above except the plain nested-instance case.
One known limitation that will show up while testing and is not this issue's to fix: sibling instances sharing a Figma name collapse to a single anatomy element, because anatomy and elements key by layer name. ADR-044 is the accepted answer and is unimplemented. Expect three identically-named cards to read as one, and do not file it again.