Skip to content

Slotted content with negative itemSpacing does not overlap in web components #361

Description

@nathanacurtis

Problem

A negative itemSpacing means children overlap. CSS expresses that as a negative margin on each child after the first, which the generated stylesheet now emits. React honours it. Web components do not.

Two compounding reasons:

  1. Slot content is projected through a holder, so the holder is the only assigned node — and ::slotted() cannot reach a slotted node's descendants.
  2. Scaffolds set :host { display: contents }. A boxless element cannot take a margin, so styling the host is inert whichever route reaches it.

Affected today:

  • Avatar Group — three avatars sit side by side instead of overlapping by 12px
  • Bottom Bar — items should overlap by 4px

Attempted and reverted

Inlining display: inline-flex alongside the margin on composed children works for hug/fixed children, but boxing the host makes it the flex item instead of the inner root — so any child sized Fill stops growing, because flex lives on the inner root and does not transfer. In Bottom Bar, whose items all fill, the first item absorbed the row while the other two collapsed.

Boxing every child is no better: they lose Fill together.

Solution

Reconcile outside-in spacing with display: contents and Fill sizing. Options, none yet chosen:

  • Give hosts a box by default and transfer sizing to the host rather than the inner root
  • Keep display: contents and express overlap in the child's own stylesheet
  • Apply the inline technique only where children are hug/fixed, on the grounds that overlap and fill are contradictory intents

The first two are the real fixes. The third needs a reliable signal for "this child fills", which the spec does not currently carry — Bottom Bar's fill comes from a component prop rather than element styles.

Acceptance criteria

  • Avatar Group's avatars overlap in web components as they do in React and in Figma
  • Bottom Bar's items overlap and still fill
  • React output is unchanged

Workspace

Surfaced during component-by-component polish, reviewing React and web component output side by side in one Storybook.

Impacted code

  • slot content composition in the web components transform package
  • scaffold :host styling in the same package
  • the css transform's overlap rule, which already emits correctly for React

Notes

Related to the slot-naming convention issue: a default slot would make each child an assigned node and reachable by ::slotted(), but would still not help while hosts are boxless.


Implementation details are tracked internally.

Metadata

Metadata

Assignees

Type

Projects

  • Status
    Backlog

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions