Skip to content

fix(sidebar): align a group's children with its label, not its icon - #2103

Merged
markdumay merged 1 commit into
mainfrom
fix/sidebar-icon-child-indent
Aug 1, 2026
Merged

fix(sidebar): align a group's children with its label, not its icon#2103
markdumay merged 1 commit into
mainfrom
fix/sidebar-icon-child-indent

Conversation

@markdumay

Copy link
Copy Markdown
Collaborator

Follow-on to #2102, found on a consuming site's deploy preview: with icons on, a group's children sit slightly left of the label they belong to, and the hierarchy reads as broken.

Cause

A leading icon pushes the parent's own label right by the icon width plus its me-1 gutter — 24px at the default size. The nested list only carries ps-3, which is 16px. The children are therefore 8px short of their parent's label.

The fix

li:has(> .sidebar-item-group svg.svg-inline--fa) > .collapse > .btn-toggle-nav {
    padding-left: calc(1.25rem + 0.25rem) !important;   // fa-fw width + me-1
}

:has() is already used in this file (_sidebar.scss:540) and in _card.scss, so it introduces no new idiom.

Scoping it this way means it holds however the icon arrived — a pre field on a data-file menu, or a page's icon via navigation.sidebarIcons — with no template or config change. Only the first nested list needs shifting; everything deeper is indented relative to it and follows.

Evidence

Icon on the top level only, reading the first visible glyph of each row:

Row Before After
Guides (has icon) 104 104
Organization 96 104
Invite a Member 112 120

Organization now starts exactly where its parent's label does, which was the reported problem.

No-op without icons

The risk in touching a shared sidebar is the sidebars that were already fine. I removed the icons from the same site and rebuilt: the ladder stays 80 / 96 / 112 and nested lists keep their 16px padding, so :has() never matches and nothing moves.

pnpm test passes.

A leading icon pushes the parent's own label right by the icon width
plus its `me-1` gutter - 24px at the default size. The nested list only
carries `ps-3`, which is 16px, so the children landed 8px to the *left*
of the label they belong to and the hierarchy read as broken.

Scoped with `:has()`, an idiom this file already uses, so it holds
however the icon arrived - a `pre` field on a data-file menu or a page
`icon` via `navigation.sidebarIcons` - and needs no template or config
change. Only the first nested list is shifted; everything deeper is
indented relative to it and follows.

Measured on a docs sidebar with icons on its top level, reading the
first visible glyph of each row:

    row                 before   after
    Guides (icon)          104     104
    Organization            96     104
    Invite a Member        112     120

Organization now starts exactly where its parent's label does.

Verified to be a no-op without icons by removing the icons and
rebuilding: the ladder stays 80 / 96 / 112 and nested lists keep their
16px padding, so `:has()` never matches and existing sidebars are
untouched.
@netlify

netlify Bot commented Aug 1, 2026

Copy link
Copy Markdown

Deploy Preview for gethinode-demo ready!

Name Link
🔨 Latest commit 52a5129
🔍 Latest deploy log https://app.netlify.com/projects/gethinode-demo/deploys/6a6e0ebbbacffa0008cae4dc
😎 Deploy Preview https://deploy-preview-2103--gethinode-demo.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@markdumay
markdumay merged commit 715cb72 into main Aug 1, 2026
17 checks passed
@markdumay

Copy link
Copy Markdown
Collaborator Author

🎉 This PR is included in version 3.13.1 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

LeonarddeR pushed a commit to LeonarddeR/hinode that referenced this pull request Aug 1, 2026
Reported after gethinode#2103 shipped: the child items visibly shift on load.

The sidebar HTML is cached per section and the collapse trail is
expanded client side, so the nested list goes from display:none to
visible after first paint. A `:has()` selector has to be re-resolved at
that point, and a browser is free to paint the old `ps-3` first and
correct it a frame later - which is exactly what the shift looks like.

The template already knows whether the group has an icon, so it now
emits `sidebar-nav-icon-indent` in place of `ps-3` and the rule is a
plain class selector. The value is in the cached markup, so it is right
from the first paint with no re-resolution and no dependence on when
the collapse opens.

Geometry is unchanged from gethinode#2103 - Guides 104, Organization 104, Invite
a Member 120, with the icon-bearing lists at 24px and the rest at 16px.
Groups without an icon keep `ps-3` exactly as before, now by emitting a
different class rather than by failing to match a selector.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant