Skip to content

fix: keep sd-breadcrumb separator spacing when a CSS reset is applied - #3378

Closed
AaronWeber90 wants to merge 2 commits into
solid-design-system:mainfrom
AaronWeber90:fix/breadcrumb-spacing
Closed

AaronWeber90 wants to merge 2 commits into
solid-design-system:mainfrom
AaronWeber90:fix/breadcrumb-spacing

Conversation

@AaronWeber90

Copy link
Copy Markdown

Description:

Reported by a consuming team: the breadcrumb separators lose their spacing as soon as the surrounding app ships a CSS reset (Tailwind v4 Preflight in their case). They embed the app in a Shadow DOM portal, so they have to include Preflight themselves and cannot simply skip it.

Root cause

mx-2 on the separator compiled to margin-inline: var(--sd-spacing-2) on a ::slotted() pseudo-element. Preflight resets margin: 0 on *, ::after, ::before.

This is not a specificity issue. Slotted elements live in the document tree, and per CSS Cascade Level 4 a declaration from a shadow tree always loses against a declaration from the document tree for normal (non-!important) rules — regardless of specificity. Verified in the browser: an explicit margin-inline: 8px instead of the utility class is overridden just the same, so the originally suggested fix would not have helped.

Fix

The spacing now comes from flex gaps instead of a margin on the pseudo-element:

  • gap-2 on [part="list"] provides the space to the right of the separator. It lives inside the shadow root, so no outer stylesheet can reach it.
  • gap-2 on ::slotted(sd-breadcrumb-item) provides the space to the left of the separator. gap is not touched by Preflight, normalize.css, sanitize.css, Bootstrap Reboot or any other common reset — unlike margin, padding and border.
  • sd-dropdown::after keeps its mx-2. It is rendered inside the shadow root and was never affected; it only needed its own rule because it previously shared the selector with the slotted separator.
  • handleTruncation() now accounts for the list gap, which is no longer part of the items' bounding boxes.

No !important and no public API change.

Verification

Measured in a browser against the built bundle, horizontal distance between the breadcrumb links:

without reset with Preflight-style reset
before 20px 4px
after 20px 20px

Truncation thresholds after the fix are identical to the previous behaviour without a reset (checked at 1300 / 400 / 320 / 280 / 240 / 200 / 160px container width). Unit tests: 887 passed, 0 failed.

As a side effect the separator spacing is now overridable by consumers via sd-breadcrumb::part(list) { gap: ... }, and the truncation logic picks that up automatically since it reads the computed gap.

Definition of Reviewable:

  • E2E tests (features, a11y, bug fixes) are created/updated
  • Stories (features, a11y) are created/updated
  • relevant tickets are linked

Outer CSS resets such as Tailwind v4 Preflight take precedence over margins on ::slotted() pseudo-elements, which collapsed the breadcrumb separator spacing. The spacing now comes from flex gaps, which no common reset touches. The truncation measurement accounts for the list gap since it is no longer part of the items' bounding boxes.
@changeset-bot

changeset-bot Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: c95cc6e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@solid-design-system/components Patch
@solid-design-system/mcp Patch
@solid-design-system/styles Patch
@solid-design-system/tokens Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

auroraVasconcelos added a commit that referenced this pull request Oct 16, 2026
…#3406)

PR from: #3378

## Description:

Reported by a consuming team: the breadcrumb separators lose their
spacing as soon as the surrounding app ships a CSS reset (Tailwind v4
Preflight in their case). They embed the app in a Shadow DOM portal, so
they have to include Preflight themselves and cannot simply skip it.

### Root cause

`mx-2` on the separator compiled to `margin-inline: var(--sd-spacing-2)`
on a `::slotted()` pseudo-element. Preflight resets `margin: 0` on `*,
::after, ::before`.

This is **not** a specificity issue. Slotted elements live in the
document tree, and per CSS Cascade Level 4 a declaration from a shadow
tree always loses against a declaration from the document tree for
normal (non-`!important`) rules — regardless of specificity. Verified in
the browser: an explicit `margin-inline: 8px` instead of the utility
class is overridden just the same, so the originally suggested fix would
not have helped.

### Fix

The spacing now comes from flex gaps instead of a margin on the
pseudo-element:

- `gap-2` on `[part="list"]` provides the space to the right of the
separator. It lives inside the shadow root, so no outer stylesheet can
reach it.
- `gap-2` on `::slotted(sd-breadcrumb-item)` provides the space to the
left of the separator. `gap` is not touched by Preflight, normalize.css,
sanitize.css, Bootstrap Reboot or any other common reset — unlike
`margin`, `padding` and `border`.
- `sd-dropdown::after` keeps its `mx-2`. It is rendered inside the
shadow root and was never affected; it only needed its own rule because
it previously shared the selector with the slotted separator.
- `handleTruncation()` now accounts for the list gap, which is no longer
part of the items' bounding boxes.

No `!important` and no public API change.

### Verification

Measured in a browser against the built bundle, horizontal distance
between the breadcrumb links:

| | without reset | with Preflight-style reset |
| --- | --- | --- |
| before | 20px | **4px** |
| after | 20px | **20px** |

Truncation thresholds after the fix are identical to the previous
behaviour without a reset (checked at 1300 / 400 / 320 / 280 / 240 / 200
/ 160px container width). Unit tests: 887 passed, 0 failed.

As a side effect the separator spacing is now overridable by consumers
via `sd-breadcrumb::part(list) { gap: ... }`, and the truncation logic
picks that up automatically since it reads the computed gap.

## Definition of Reviewable:
- [x] E2E tests (features, a11y, bug fixes) are created/updated
<!-- Purely visual fix, so it is covered by a Chromatic screenshot story
instead: the new `Preflight Reset` story renders the breadcrumb under a
scoped Preflight excerpt. -->
- [x] Stories (features, a11y) are created/updated
- [ ] relevant tickets are linked

---------

Authored-by: Aaron <aaronweber@gmx.at>
@github-project-automation github-project-automation Bot moved this from 🏗 In progress to ✅ Done in Solid Design System Project Board Oct 22, 2026
@mariohamann

Copy link
Copy Markdown
Contributor

442288d

Resolved here. Thanks @AaronWeber90 !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Development needs changes in code

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

3 participants