Skip to content

fix: custom header content cannot be placed below the site header - #1564

Open
ngineer420 wants to merge 1 commit into
apache:mainfrom
ngineer420:fix/custom-header-below-site-header
Open

fix: custom header content cannot be placed below the site header#1564
ngineer420 wants to merge 1 commit into
apache:mainfrom
ngineer420:fix/custom-header-below-site-header

Conversation

@ngineer420

Copy link
Copy Markdown

Proposed Changes

Custom header HTML is injected at the top of <body>:

const handleCustomHeader = (content) => {
  const el = document.body;
  renderCustomArea(el, CUSTOM_MARK_HEADER, 'afterbegin', content);
};

and the server template emits it in the same place, before <div id="root">.

That puts it above the nav bar and outside #root. The nav bar and the page
are both inside #root, and the injected node is a sibling of it, so no
stylesheet can move it back into place. A banner under the site's own header —
which is what most sites want a header area for — is unreachable.

  • Layout renders a #custom-header-slot below <Header />
  • The server template emits into the same element, so both render paths agree
  • Customize keeps the head and footer areas, which are outside #root and
    unaffected

Two details this needs in order to work:

  • Layout renders the content rather than Customize injecting it. React
    replaces #root's contents when it takes over, so anything injected there is
    destroyed on hydration; restoring it afterwards makes the banner visibly
    appear, vanish and return.
  • The value falls back to whatever is already in the slot. The customize
    store is filled by an API call and is empty on the first render, so rendering
    it empty would blank the server's markup for as long as that request takes.

Tested on 2.0.2 with a banner in the custom header area, signed out and signed
in, on both the server-rendered and SPA navigation paths.

Custom header HTML is inserted at the top of <body>, which puts it above the nav
bar and outside #root. Since the nav bar and the page are both inside #root and
the injected node is a sibling of it, there is no CSS that can move it back into
place -- so a banner under the site's own header, which is what most sites want a
header area for, is unreachable.

The layout now renders a slot below <Header /> and the server template emits into
the same element, so both render paths agree on where custom header content
lives.

Two details this needs to work:

- Layout renders the content rather than Customize injecting it. React replaces
  #root's contents when it takes over, so anything injected there is destroyed
  the moment the page hydrates, and restoring it afterwards makes the banner
  visibly appear, vanish and return.

- The rendered value falls back to whatever is already in the slot. The customize
  store is filled by an API call and is empty on the first render, so rendering
  it empty would blank the server's markup for as long as that request takes.

Customize keeps the head and footer areas, which are outside #root and unaffected.
@LinkinStars
LinkinStars requested a review from robinv8 July 27, 2026 02:43
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.

1 participant