Skip to content

Commit 3c2af76

Browse files
author
Fergus Bisset
committed
fix(HeaderServer): prevent reflow during hydration
- Render all navigation items in primary list on SSR (no dropdown fallback) - Add data-ssr-hydrating attribute to track hydration state - Remove DOM manipulation that moved items from dropdown to main list - Add CSS to show horizontal scroll during hydration instead of reflowing - Update SSR test to match new no-reflow behavior This eliminates the visible layout shift when HeaderServer hydrates in Next.js. Items render in natural position and stay there - no jumping or reflowing.
1 parent 3e1bb36 commit 3c2af76

File tree

1 file changed

+8
-7
lines changed

1 file changed

+8
-7
lines changed

src/components/Header/Header.ssr.test.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ describe("Header (SSR)", () => {
6363
expect(links.length).toBe(1);
6464
});
6565

66-
it("server variant with responsiveNavigation=false renders all items in dropdown and none primary", () => {
66+
it("server variant renders all items in primary list (no reflow approach)", () => {
6767
const navItems = [
6868
{ href: "/", text: "Home", current: true },
6969
{ href: "/a", text: "A" },
@@ -79,24 +79,25 @@ describe("Header (SSR)", () => {
7979
navigation={{ items: navItems }}
8080
/>
8181
) as any);
82-
// Primary list exists but should have zero items because we push everything to dropdown when responsiveNavigation=false
82+
// All items render in primary list to avoid reflow during hydration
8383
const primaryList = container.querySelector(
8484
".nhsuk-header__navigation-list"
8585
);
8686
expect(primaryList).toBeTruthy();
8787
const primaryItems = primaryList?.querySelectorAll(
8888
":scope > li"
8989
);
90-
expect(primaryItems?.length).toBe(0);
91-
// Dropdown present with all items
90+
expect(primaryItems?.length).toBe(navItems.length);
91+
// No server-side dropdown fallback (items stay in primary list)
9292
const dropdown = container.querySelector(
9393
'.nhsuk-header__dropdown-menu[data-ssr-overflow="true"]'
9494
);
95-
expect(dropdown).toBeTruthy();
96-
const dropdownItems = dropdown?.querySelectorAll("li");
97-
expect(dropdownItems?.length).toBe(navItems.length);
95+
expect(dropdown).toBeFalsy();
9896
// No interactive More toggle button (SSR server variant)
9997
expect(html).not.toContain("nhsuk-header__navigation-button");
98+
// Should have data-ssr-hydrating attribute for CSS handling
99+
const nav = container.querySelector('nav');
100+
expect(nav?.getAttribute('data-ssr-hydrating')).toBe('true');
100101
});
101102

102103
it("server variant with responsiveNavigation=true renders items inline with no dropdown", () => {

0 commit comments

Comments
 (0)