Skip to content

Comments

fix: prevent sidebar jitter, scroll passthrough, and nav z-index overlap#119

Open
opentabs-dev wants to merge 1 commit intoLogging-Studio:mainfrom
opentabs-dev:fix/sidebar-toc-scroll-passthrough
Open

fix: prevent sidebar jitter, scroll passthrough, and nav z-index overlap#119
opentabs-dev wants to merge 1 commit intoLogging-Studio:mainfrom
opentabs-dev:fix/sidebar-toc-scroll-passthrough

Conversation

@opentabs-dev
Copy link

@opentabs-dev opentabs-dev commented Feb 21, 2026

Summary

This PR fixes three bugs in the docs layout that affect scrolling behaviour and visual layering.


Bug 1 — Sidebar jitter while scrolling

Problem: The sidebar uses position: sticky with self-start inside a flex container. Because sticky elements still participate in layout flow, the browser recalculates their position on every scroll frame. This causes a 1–2px drift before the element is re-pinned, visible as a subtle jitter.

Fix: Replace sticky with fixed positioning on the sidebar wrapper. A fixed element is composited independently of page scroll — it never moves. The left offset uses max(0px, calc((100vw - 80rem) / 2)) so the sidebar stays aligned with the max-w-7xl centered container on wide screens.


Bug 2 — Scroll events pass through sidebar and TOC to the page

Problem: Both the sidebar and the "On this Page" TOC box use overflow-y-auto. This only creates a scroll container when content overflows. When content is shorter than the container — or when the pointer is over a gap between items — the browser does not consider the element a scroll target and routes wheel events directly to the page, scrolling the main content instead.

Fix: Replace overflow-y-auto with overflow-y-scroll on both elements. This forces them to always be scroll containers, so wheel events are always captured regardless of content height. Add overscroll-y-contain to prevent scroll chaining to the page when the element reaches its boundary. The existing sidebar-scroll CSS class already hides the forced scrollbar track visually — no visual regression.


Bug 3 — TopNav z-index too low, page content renders over it

Problem: The <nav> has z-1. Any page content with a higher z-index (e.g. code block copy buttons) renders on top of the sticky nav while scrolling.

Fix: Raise nav to z-50. Also removed a stale z-99 class from the inner <nav> in SideNav which had no effect.


Files Changed

  • app/(docs)/docs/layout.tsx — fixed sidebar positioning
  • components/SideNav.tsxoverflow-y-scroll, overscroll-y-contain, removed stale z-index
  • components/TableOfContents.tsxoverflow-y-scroll, overscroll-y-contain
  • components/TopNav.tsx — raised z-index to z-50

Testing

Tested locally with pnpm dev. Verified:

  • Sidebar no longer jitters when scrolling main content
  • Scrolling over sidebar gaps and TOC padding no longer scrolls the page
  • Nav remains above all page content while scrolling

Summary by CodeRabbit

  • Refactor
    • Updated documentation sidebar to use fixed positioning for improved layout consistency
    • Simplified navigation layout and removed responsive animations
    • Adjusted scrolling behavior for table of contents
    • Enhanced stacking order for top navigation visibility

Three related bugs fixed:

1. Sidebar jitter on scroll
   sticky + self-start in a flex container causes 1-2px drift each frame
   as the browser recalculates position. Fixed by making the sidebar fixed
   so it is composited independently of page scroll. left tracks the
   max-w-7xl centered container via max(0px, (100vw - 80rem) / 2).

2. Scroll passthrough on sidebar and TOC
   overflow-y-auto only intercepts wheel events when content overflows.
   Hovering over gaps between items or on a short sidebar sends scroll
   to the page instead. Fixed with overflow-y-scroll (always a scroll
   container) and overscroll-y-contain (no chaining at boundaries).
   sidebar-scroll already hides the forced scrollbar track visually.

3. TopNav z-index too low (z-1)
   Page content with higher z-index (copy buttons, etc.) rendered over
   the sticky nav while scrolling. Fixed by raising nav to z-50.

Files changed:
- app/(docs)/docs/layout.tsx
- components/SideNav.tsx
- components/TableOfContents.tsx
- components/TopNav.tsx
@vercel
Copy link

vercel bot commented Feb 21, 2026

@opentabs-dev is attempting to deploy a commit to the Retro UI Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 21, 2026

📝 Walkthrough

Walkthrough

The documentation layout transitions from a responsive in-flow sidebar to a fixed 60px left sidebar with centered content area. Accompanying changes simplify the sidebar animation behavior, adjust overflow and scrolling properties in the table of contents, and increase the top navigation's z-index stacking order for proper layering.

Changes

Cohort / File(s) Summary
Layout Restructuring
app/(docs)/docs/layout.tsx, components/SideNav.tsx
Layout converted from responsive nested structure to fixed sidebar (60px width, left-positioned) with centered content container (max 80rem). Sidebar animation and responsive max-height behaviors removed; layout now uses static dimensions with lg breakpoint visibility control.
Overflow & Stacking Adjustments
components/TableOfContents.tsx, components/TopNav.tsx
TableOfContents overflow behavior changed from overflow-y-auto to overflow-y-scroll with overscroll-y-contain. TopNav z-index increased from z-1 to z-50 for proper stacking above other elements.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 Hop, hop! The sidebar stands so tall,
Fixed at the edge, responsive to all,
Scrollbars dance and layers align,
A layout refined, oh how it does shine!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the three main fixes: sidebar jitter prevention, scroll passthrough prevention, and nav z-index overlap resolution, directly matching the PR's core objectives.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
app/(docs)/docs/layout.tsx (1)

17-17: Hardcoded 80rem duplicates the max-w-7xl token.

The calc((100vw - 80rem) / 2) in the left offset assumes max-w-7xl is 80rem. If the Tailwind config ever customizes that breakpoint, this value would silently drift. Consider extracting a CSS custom property (e.g., --container-max: 80rem) used by both the container and the offset, or leave a comment noting the coupling.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/`(docs)/docs/layout.tsx at line 17, The hardcoded "80rem" in the lg:left
calc inside the div class (the element with className "fixed top-28 hidden
h-[calc(100vh-7rem)] w-60 lg:left-[max(0px,calc((100vw-80rem)/2))] lg:block")
duplicates the max-w-7xl token and can drift if Tailwind config changes; replace
the literal with a CSS custom property (for example --container-max) used by
both the container and this offset (update the container element that uses
max-w-7xl to set --container-max: 80rem or the shared value) or, if you cannot
change the container, add a clear comment next to the lg:left usage noting the
coupling so future maintainers know why 80rem is required.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/`(docs)/docs/layout.tsx:
- Line 17: The fixed sidebar in layout.tsx uses a hardcoded "top-28" value which
can mismatch the actual TopNav height; replace the hardcoded top with a dynamic
value by exposing the TopNav height as a CSS variable or measured value and
using that for the sidebar top. Specifically, have the TopNav component set
--topnav-height (or expose its clientHeight via a ref/useEffect) and update the
sidebar div currently using "top-28" to use top: var(--topnav-height) (or inline
style from the measured value) so the sidebar always aligns without gap/overlap;
then test around the lg breakpoint where the promo banner wraps.

---

Nitpick comments:
In `@app/`(docs)/docs/layout.tsx:
- Line 17: The hardcoded "80rem" in the lg:left calc inside the div class (the
element with className "fixed top-28 hidden h-[calc(100vh-7rem)] w-60
lg:left-[max(0px,calc((100vw-80rem)/2))] lg:block") duplicates the max-w-7xl
token and can drift if Tailwind config changes; replace the literal with a CSS
custom property (for example --container-max) used by both the container and
this offset (update the container element that uses max-w-7xl to set
--container-max: 80rem or the shared value) or, if you cannot change the
container, add a clear comment next to the lg:left usage noting the coupling so
future maintainers know why 80rem is required.

<div className="mx-auto max-w-7xl">
{/* Sidebar — fixed to the viewport, left-aligned with the max-w-7xl (80rem)
centered container. On screens narrower than 80rem, left is 0. */}
<div className="fixed top-28 hidden h-[calc(100vh-7rem)] w-60 lg:left-[max(0px,calc((100vw-80rem)/2))] lg:block">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

top-28 (7rem) is coupled to the TopNav's rendered height — verify no gap or overlap.

The TopNav has a variable-height promotional banner + h-16 nav bar + 2px border. If the banner text wraps (e.g., on a screen just past the lg breakpoint), the total height could exceed 7rem, causing the sidebar to tuck under the nav. Conversely, if the banner is shorter than expected, there's a visible gap.

Since you've verified locally, this is likely fine, but it's worth testing at viewport widths near 1024px where the sidebar first appears and the banner is most likely to wrap.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/`(docs)/docs/layout.tsx at line 17, The fixed sidebar in layout.tsx uses
a hardcoded "top-28" value which can mismatch the actual TopNav height; replace
the hardcoded top with a dynamic value by exposing the TopNav height as a CSS
variable or measured value and using that for the sidebar top. Specifically,
have the TopNav component set --topnav-height (or expose its clientHeight via a
ref/useEffect) and update the sidebar div currently using "top-28" to use top:
var(--topnav-height) (or inline style from the measured value) so the sidebar
always aligns without gap/overlap; then test around the lg breakpoint where the
promo banner wraps.

@vercel
Copy link

vercel bot commented Feb 22, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
retro-ui Ready Ready Preview, Comment Feb 22, 2026 4:50pm

Request Review

@ariflogs
Copy link
Member

not sure about the issue though. Can you share a before and after screenshot?

@opentabs-dev
Copy link
Author

not sure about the issue though. Can you share a before and after screenshot?

Sure, i think i will do a screenrecording. Also could you delete this #118 (comment) comment? thank you

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants