🐛 Bug: docs.copilotkit.ai: the announcement banner renders only after hydration, so the header and content jump down 40px on every load · Issue #7825 · CopilotKit/CopilotKit · GitHub
Skip to content

🐛 Bug: docs.copilotkit.ai: the announcement banner renders only after hydration, so the header and content jump down 40px on every load #7825

Open

Description

@Laptopmini

♻️ Reproduction Steps

  1. Open https://docs.copilotkit.ai/quickstart in a fresh browser profile (banner not dismissed), at any width. It's most visible below 1280px, where the fixed MobileTopNav is shown.
  2. Watch the first seconds of the load. DevTools network throttling makes it easier to see.

Measured with headless Chromium on the live site, iPhone 13 viewport (positions in CSS px):

✅ Expected Behavior

The first paint already has the final layout: the banner (or the space for it), with the header and content where they end up. A reader who dismissed the banner doesn't see it flash in.

❌ Actual Behavior

src/components/banners.tsx returns null until a useEffect has run (if (!hydrated || dismissed) return null), because it reads the dismissed state from localStorage. The same effect is what sets --fd-banner-height on (40px or 0px). So:

  • Before hydration, there's no banner and --fd-banner-height is unset. MobileTopNav's top-(--fd-banner-height) has no fallback, so the fixed nav falls back to its static position (y = 8 below md, 12 at md).
  • After hydration, the banner renders, the variable becomes 40px, and the header and everything below it move down by about 32–40px.

The jump happens on every page load for readers who haven't dismissed the banner. For readers who have, the variable goes from unset to 0px, which also moves the fixed nav by 8–12px.

Chrome's Layout Instability API reports no layout-shift entries for this jump (CLS 0 in the same runs, layout-shift supported), so Lighthouse and Web Vitals won't flag it. The positions above come from getBoundingClientRect sampling.

Possible fix:

  • Render the banner on the server, so it's in the first paint.
  • Decide dismissal before paint with a small inline script in that reads the localStorage flags and sets --fd-banner-height (or a class on that hides the banner). That's the same approach next-themes uses to avoid a theme flash.
  • Give top-(--fd-banner-height) a fallback, e.g. top-[var(--fd-banner-height,0px)].

I'm happy to open a PR.

Screenshots

Image Image

𝌚 CopilotKit Version

docs.copilotkit.ai (showcase/shell-docs @ main 500b40efb): next 16.2.6, fumadocs-core/ui 16.8.12, react 19.2

📄 Logs (Optional)

t≈100ms   MobileTopNav top=8   h1 top=136   --fd-banner-height unset   banner absent
t≈2800ms  MobileTopNav top=40  h1 top=176   --fd-banner-height 40px    banner 0–40

Activity

  1. copilotkit-outpost-bot commented on Oct 14, 2026

    @copilotkit-outpost-bot

    This is a docs-site layout issue, not a CopilotKit SDK bug — nothing in the retrieved sources covers banners.tsx, --fd-banner-height, or the MobileTopNav positioning logic you've described, so I don't have enough to comment on the internals or validate the fix paths.

    Your analysis is thorough and the PR offer is the right next step — engineering will need to verify and pick the approach. I'm escalating this to the team.


    🤖 Generated by CopilotKit AI Support · Documentation


    Was this helpful? React with 👍 or 👎

  2. choudhary-lokeshh commented on Oct 21, 2026

    @choudhary-lokeshh

    Hi! I'd like to work on this if it's still available.

    @Laptopmini, I saw you offered to open a PR. If you're already working on it, I'll step back.

    Otherwise, my plan:

    1. Add a small inline script in <head> that reads the dismissal flags from localStorage and sets --fd-banner-height before the first paint (the same trick next-themes uses to avoid a theme flash).
    2. Render the banner on the server so it's part of the first paint, and hide it with CSS when it was dismissed.
    3. Add a 0px fallback to MobileTopNav's top-(--fd-banner-height).

    Does this approach sound good to the maintainers?

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions