Skip to content

feat(banner): add x for closing#9008

Open
avivkeller wants to merge 3 commits into
mainfrom
banner-close
Open

feat(banner): add x for closing#9008
avivkeller wants to merge 3 commits into
mainfrom
banner-close

Conversation

@avivkeller

@avivkeller avivkeller commented Jul 14, 2026

Copy link
Copy Markdown
Member

Makes the banner close-able.

Note: This just updated ui-components, and doesn't touch Next.js + cookie handling
Screenshot 2026-07-14 at 12 15 13 PM

Copilot AI review requested due to automatic review settings July 14, 2026 19:13
@avivkeller avivkeller requested a review from a team as a code owner July 14, 2026 19:13
@vercel

vercel Bot commented Jul 14, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
nodejs-org Ready Ready Preview Jul 14, 2026 7:56pm

Request Review

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@cursor

cursor Bot commented Jul 14, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
UI-only banner behavior with client-side localStorage; minor hydration flash possible when a banner was previously dismissed.

Overview
Adds an optional close (×) control to the shared Banner component via onClose, with absolute-positioned button styling and a Storybook Dismissible example. @node-core/ui-components is bumped to 1.7.2.

The site WithBanner wrapper is now a client component: it wires onClose to hide the banner and persist dismissal in localStorage (key banner-dismissal, value matched to banner.text), reading that state after hydration so SSR still renders the banner until the client knows it was dismissed.

Reviewed by Cursor Bugbot for commit b2dc64f. Bugbot is set up for automated code reviews on this repo. Configure here.

@codecov

codecov Bot commented Jul 14, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 74.54%. Comparing base (61cd932) to head (b2dc64f).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9008      +/-   ##
==========================================
- Coverage   74.58%   74.54%   -0.04%     
==========================================
  Files         100      100              
  Lines        8801     8801              
  Branches      324      325       +1     
==========================================
- Hits         6564     6561       -3     
- Misses       2233     2236       +3     
  Partials        4        4              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

Comment on lines +24 to +25
const [dismissed, setDismissed] = useState(false);
if (dismissed) {return null;}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't think the banner needs to do its own state management, let the consumer of the component handle that with the onClose

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

We could, however, that would require duplicating the state logic in doc-kit, and here

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think that's fine, as we're going to need to tie this to a cookie/localStorage anyway

Comment thread packages/ui-components/src/Common/Banner/index.tsx
Comment thread packages/ui-components/src/Common/Banner/index.tsx
Comment thread packages/ui-components/src/Common/Banner/index.tsx Outdated
transition-colors
hover:text-white;
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Close button overlaps content

Medium Severity

The close control is absolute with right-4 while the banner still uses symmetric px-8 and centered content. Nothing reserves space for the button, so on narrower viewports or with longer banner text the label, link, or icon can sit under the ×. Elsewhere in this package, absolute controls get matching padding so content stays clear.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit bd140ea. Configure here.

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

📦 Build Size Comparison

Summary

Metric Value
Old Total First Load JS 10.70 MB
New Total First Load JS 10.64 MB
Delta -60.08 KB (-0.55%)

Changes

🔄 Modified Routes (4)
Route Old First Load JS New First Load JS Delta
/[locale] 2.55 MB 2.54 MB 📉 -15.02 KB (-0.57%)
/[locale]/[...path] 2.55 MB 2.54 MB 📉 -15.02 KB (-0.57%)
/[locale]/blog/[...path] 2.55 MB 2.54 MB 📉 -15.02 KB (-0.57%)
/[locale]/download/archive/[version] 2.55 MB 2.54 MB 📉 -15.02 KB (-0.57%)

@bjohansebas bjohansebas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think that if we ever update the banner and a user previously dismissed it, we should show it to them again

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit b2dc64f. Configure here.

if (banner) {
setDismissed(localStorage.getItem(STORAGE_KEY) === banner.text);
}
}, [banner]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Dismissed banner flashes on load

Medium Severity

Dismissal is restored from localStorage only inside useEffect, after the first paint. dismissed starts as false, so a previously closed banner still SSR-renders and shows briefly, then disappears and shifts the header/nav on every load.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit b2dc64f. Configure here.

>
<span aria-hidden="true">&times;</span>
</button>
)}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Close label not localizable

Low Severity

The close control hardcodes aria-label="Close banner" on the button, and that string is not overridable via props. Extra HTML attributes only spread onto the section, so consumers such as withBanner cannot pass a translated label despite already using useTranslations for the banner itself.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit b2dc64f. Configure here.

// rendered on the server and hidden after hydration if previously dismissed
useEffect(() => {
if (banner) {
setDismissed(localStorage.getItem(STORAGE_KEY) === banner.text);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

there are a thing here localstroage is shared with api docs but not with sub domain like undici.nodejs.org

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Then I guess a cookie would solve that, right?

@AugustinMauroy

Copy link
Copy Markdown
Member

there are a flash humm not fan of it maybe not display it by default. also what will happen on doc-kit since it's already flash when fetching site.json

@trivikr

trivikr commented Jul 14, 2026

Copy link
Copy Markdown
Member

To avoid flash, can we dismiss it by default and show only if the value is not set?

Screen recording of flash on reload post dismiss
nodejs-banner-flash-on-reload-post-dismiss.mov

@trivikr

trivikr commented Jul 15, 2026

Copy link
Copy Markdown
Member

Fixes: #6292

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.

6 participants