Skip to content

fix: hide feedback button when it overlaps with navbar#735

Open
an1ndra wants to merge 3 commits intoTanStack:mainfrom
an1ndra:add_button_fix
Open

fix: hide feedback button when it overlaps with navbar#735
an1ndra wants to merge 3 commits intoTanStack:mainfrom
an1ndra:add_button_fix

Conversation

@an1ndra
Copy link
Copy Markdown
Contributor

@an1ndra an1ndra commented Feb 26, 2026

Fix: #730

Before:
Screenshot from 2026-02-27 02-11-59

After:
Screenshot from 2026-02-27 02-10-07

Summary by CodeRabbit

  • Bug Fixes
    • Fixed button visibility handling when scrolling near the navigation bar.

@netlify
Copy link
Copy Markdown

netlify bot commented Feb 26, 2026

👷 Deploy request for tanstack pending review.

Visit the deploys page to approve it

Name Link
🔨 Latest commit 784a7b1

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 12, 2026

⚠️ No Changeset found

Latest commit: d5e7b82

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

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

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 3, 2026

📝 Walkthrough

Walkthrough

The BlockButton component in DocFeedbackProvider.tsx now tracks scroll position via a scrollY state that updates on window scroll and resize events. When determining whether to display the button, it measures the block's position and hides the button if it would overlap with the navbar, resolving visual overlap issues.

Changes

Cohort / File(s) Summary
Button Visibility Logic
src/components/DocFeedbackProvider.tsx
Added scrollY state tracking on window scroll/resize events. Implemented conditional rendering logic that hides the BlockButton when its computed position would overlap the navbar, by reading the --navbar-height CSS variable and comparing against the block's bounding rectangle.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A button was lost 'neath the navbar's great might,
Covered and hiding from UI sight,
Now with scroll-tracking, positions are true,
The "+" stays visible—no overlap to view!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: hiding the feedback button when it overlaps with the navbar, which directly addresses the primary objective.
Linked Issues check ✅ Passed The PR addresses the core requirement from issue #730 by implementing logic to hide the feedback button when it would overlap with the navbar, preventing visual overlap.
Out of Scope Changes check ✅ Passed All changes are scoped to the BlockButton component's overlap detection and hiding logic, directly addressing the navbar overlap issue without introducing unrelated modifications.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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
Copy Markdown

@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.

🧹 Nitpick comments (3)
src/components/DocFeedbackProvider.tsx (3)

415-416: Remove void scrollY - the variable is already used in the dependency array implicitly.

The void scrollY statement is a workaround to suppress an unused variable warning, but ESLint and TypeScript typically don't flag state variables as unused when they trigger re-renders. If a linter is flagging this, consider adding a comment explaining the purpose instead.

♻️ Replace with explanatory comment
-  // Suppress unused state warning - scrollY triggers re-renders
-  void scrollY
+  // Note: scrollY state is intentionally "unused" - its updates trigger re-renders
+  // so that getBoundingClientRect() returns fresh values during scroll
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/DocFeedbackProvider.tsx` around lines 415 - 416, Remove the
unnecessary "void scrollY" statement in DocFeedbackProvider (the scrollY
state/variable), and instead add a brief explanatory comment near where scrollY
is declared/used that explains it is intentionally included only to trigger
re-renders (and therefore appears in effect dependency arrays); ensure any
useEffect or hook that relies on scrollY includes it in its dependency array so
linters understand the variable is intentionally used.

405-408: Hardcoded button height may become stale if styling changes.

The buttonHeight = 24 assumes w-6 h-6 Tailwind classes (6 × 4px = 24px). If DocFeedbackFloatingButton styling changes, this will silently break the overlap calculation.

♻️ Consider extracting as a shared constant or measuring dynamically

A shared constant near DocFeedbackFloatingButton would be more maintainable:

// In DocFeedbackFloatingButton.tsx or a shared constants file
export const FEEDBACK_BUTTON_HEIGHT = 24

// Then import and use here
import { FEEDBACK_BUTTON_HEIGHT } from './DocFeedbackFloatingButton'
// ...
const buttonTop = blockRect.top - FEEDBACK_BUTTON_HEIGHT
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/DocFeedbackProvider.tsx` around lines 405 - 408, The hardcoded
buttonHeight (24) used to compute buttonTop can drift if
DocFeedbackFloatingButton's styling changes; replace the literal with a shared
exported constant (e.g., export FEEDBACK_BUTTON_HEIGHT from
DocFeedbackFloatingButton or a shared constants file) and import it here to
compute buttonTop (replace usage of buttonHeight with the imported
FEEDBACK_BUTTON_HEIGHT), or alternatively measure the actual element height at
runtime via getBoundingClientRect on the DocFeedbackFloatingButton node and use
that value to compute buttonTop so the overlap stays correct.

358-377: Consider throttling scroll handler to reduce re-render frequency.

Scroll events fire at high frequency (potentially 60+ times per second during active scrolling). Each setScrollY call triggers a re-render that runs getBoundingClientRect() and getComputedStyle() DOM queries. While { passive: true } prevents blocking the main thread, the render volume could still cause jank on lower-powered devices.

♻️ Suggested throttle implementation
   // Track scroll position to trigger re-renders for navbar overlap check
   React.useEffect(() => {
     if (!mounted) return
 
+    let rafId: number | null = null
+
     const handleScroll = () => {
-      setScrollY(window.scrollY)
+      if (rafId === null) {
+        rafId = requestAnimationFrame(() => {
+          setScrollY(window.scrollY)
+          rafId = null
+        })
+      }
     }
 
-    const handleResize = () => {
-      setScrollY(window.scrollY)
-    }
-
     window.addEventListener('scroll', handleScroll, { passive: true })
-    window.addEventListener('resize', handleResize)
+    window.addEventListener('resize', handleScroll)
 
     return () => {
       window.removeEventListener('scroll', handleScroll)
-      window.removeEventListener('resize', handleResize)
+      window.removeEventListener('resize', handleScroll)
+      if (rafId !== null) {
+        cancelAnimationFrame(rafId)
+      }
     }
   }, [mounted])
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/DocFeedbackProvider.tsx` around lines 358 - 377, The scroll
handler (handleScroll) calls setScrollY on every event causing frequent
re-renders; inside the useEffect that depends on mounted, wrap/debounce the
handler with a throttle mechanism (preferably requestAnimationFrame or a small
lodash.throttle) so setScrollY is only invoked at animation frame rate or
limited frequency, apply the same throttling to handleResize, store any RAF id
or throttle cancel token in a ref, and ensure the cleanup function cancels the
RAF or calls the throttle cancel before removing the event listeners; keep
existing event options (e.g., { passive: true }) and reference the existing
symbols mounted, handleScroll, handleResize, setScrollY, and the useEffect
cleanup to implement this.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/components/DocFeedbackProvider.tsx`:
- Around line 415-416: Remove the unnecessary "void scrollY" statement in
DocFeedbackProvider (the scrollY state/variable), and instead add a brief
explanatory comment near where scrollY is declared/used that explains it is
intentionally included only to trigger re-renders (and therefore appears in
effect dependency arrays); ensure any useEffect or hook that relies on scrollY
includes it in its dependency array so linters understand the variable is
intentionally used.
- Around line 405-408: The hardcoded buttonHeight (24) used to compute buttonTop
can drift if DocFeedbackFloatingButton's styling changes; replace the literal
with a shared exported constant (e.g., export FEEDBACK_BUTTON_HEIGHT from
DocFeedbackFloatingButton or a shared constants file) and import it here to
compute buttonTop (replace usage of buttonHeight with the imported
FEEDBACK_BUTTON_HEIGHT), or alternatively measure the actual element height at
runtime via getBoundingClientRect on the DocFeedbackFloatingButton node and use
that value to compute buttonTop so the overlap stays correct.
- Around line 358-377: The scroll handler (handleScroll) calls setScrollY on
every event causing frequent re-renders; inside the useEffect that depends on
mounted, wrap/debounce the handler with a throttle mechanism (preferably
requestAnimationFrame or a small lodash.throttle) so setScrollY is only invoked
at animation frame rate or limited frequency, apply the same throttling to
handleResize, store any RAF id or throttle cancel token in a ref, and ensure the
cleanup function cancels the RAF or calls the throttle cancel before removing
the event listeners; keep existing event options (e.g., { passive: true }) and
reference the existing symbols mounted, handleScroll, handleResize, setScrollY,
and the useEffect cleanup to implement this.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 770047cf-68db-4e2a-a362-2d7049e1a0c2

📥 Commits

Reviewing files that changed from the base of the PR and between 202961c and 784a7b1.

📒 Files selected for processing (1)
  • src/components/DocFeedbackProvider.tsx

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.

"+" icon in the docs is going over the Navbar

1 participant