From ed5f6aa2b402315a1588f75c1949b61ed52f5ee5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 Aug 2025 20:13:14 +0000 Subject: [PATCH 1/3] Initial plan From c1ecf61734dd60acc622636e1445a2b795f33104 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 Aug 2025 20:21:37 +0000 Subject: [PATCH 2/3] Add subNavigationId prop and implement deterministic ID generation for SSR compatibility Co-authored-by: mfranzke <787658+mfranzke@users.noreply.github.com> --- .../src/components/navigation-item/model.ts | 5 +++ .../navigation-item/navigation-item.lite.tsx | 10 +++++- .../navigation-item/navigation-item.spec.tsx | 33 +++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/packages/components/src/components/navigation-item/model.ts b/packages/components/src/components/navigation-item/model.ts index 807e78df61fd..bdbe8938a970 100644 --- a/packages/components/src/components/navigation-item/model.ts +++ b/packages/components/src/components/navigation-item/model.ts @@ -36,6 +36,11 @@ export type DBNavigationItemDefaultProps = { * This is for mobile navigation only, if it is set the sub-navigation is a static overlay */ subNavigationExpanded?: boolean | string; + + /** + * ID for the sub-navigation element. If not provided, a deterministic ID will be generated to ensure SSR compatibility. + */ + subNavigationId?: string; }; export type DBNavigationItemProps = DBNavigationItemDefaultProps & diff --git a/packages/components/src/components/navigation-item/navigation-item.lite.tsx b/packages/components/src/components/navigation-item/navigation-item.lite.tsx index af2f46b956da..32320c5a5cba 100644 --- a/packages/components/src/components/navigation-item/navigation-item.lite.tsx +++ b/packages/components/src/components/navigation-item/navigation-item.lite.tsx @@ -29,7 +29,7 @@ export default function DBNavigationItem(props: DBNavigationItemProps) { hasSubNavigation: true, isSubNavigationExpanded: false, autoClose: false, - subNavigationId: 'sub-navigation-' + uuid(), + subNavigationId: props.subNavigationId ?? (props.id ? `${props.id}-sub-navigation` : 'sub-navigation'), navigationItemSafeTriangle: undefined, handleNavigationItemClick: (event: any) => { if (event?.target?.nodeName === 'A') { @@ -68,6 +68,14 @@ export default function DBNavigationItem(props: DBNavigationItemProps) { } }, [props.subNavigationExpanded]); + onUpdate(() => { + // Update subNavigationId if props change + const newSubNavigationId = props.subNavigationId ?? (props.id ? `${props.id}-sub-navigation` : 'sub-navigation'); + if (state.subNavigationId !== newSubNavigationId) { + state.subNavigationId = newSubNavigationId; + } + }, [props.subNavigationId, props.id]); + onUpdate(() => { if (state.initialized && _ref) { const subNavigationSlot = _ref.querySelector('menu'); diff --git a/packages/components/src/components/navigation-item/navigation-item.spec.tsx b/packages/components/src/components/navigation-item/navigation-item.spec.tsx index aa055f6718d4..4fe216a2e67c 100644 --- a/packages/components/src/components/navigation-item/navigation-item.spec.tsx +++ b/packages/components/src/components/navigation-item/navigation-item.spec.tsx @@ -29,6 +29,39 @@ const testComponent = () => { const component = await mount(comp); await expect(component).toHaveScreenshot(); }); + + test('should use deterministic subNavigationId when id prop is provided', async ({ mount }) => { + const componentWithId = ( + + Test + + ); + const component = await mount(componentWithId); + const subNav = component.locator('menu[id="test-nav-item-sub-navigation"]'); + await expect(subNav).toBeAttached(); + }); + + test('should use provided subNavigationId when specified', async ({ mount }) => { + const componentWithSubNavId = ( + + Test + + ); + const component = await mount(componentWithSubNavId); + const subNav = component.locator('menu[id="custom-sub-nav-id"]'); + await expect(subNav).toBeAttached(); + }); + + test('should use fallback subNavigationId when no id or subNavigationId provided', async ({ mount }) => { + const componentWithoutId = ( + + Test + + ); + const component = await mount(componentWithoutId); + const subNav = component.locator('menu[id="sub-navigation"]'); + await expect(subNav).toBeAttached(); + }); }; const testA11y = () => { test('should have same aria-snapshot', async ({ mount }, testInfo) => { From 1ef965e6671fb657c339229059fb2672e07ea844 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 Aug 2025 20:24:31 +0000 Subject: [PATCH 3/3] Add documentation comments and finalize SSR fix implementation Co-authored-by: mfranzke <787658+mfranzke@users.noreply.github.com> --- .../src/components/navigation-item/navigation-item.lite.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/components/src/components/navigation-item/navigation-item.lite.tsx b/packages/components/src/components/navigation-item/navigation-item.lite.tsx index 32320c5a5cba..ba3823a90792 100644 --- a/packages/components/src/components/navigation-item/navigation-item.lite.tsx +++ b/packages/components/src/components/navigation-item/navigation-item.lite.tsx @@ -29,6 +29,10 @@ export default function DBNavigationItem(props: DBNavigationItemProps) { hasSubNavigation: true, isSubNavigationExpanded: false, autoClose: false, + // Use deterministic ID generation for SSR compatibility: + // 1. Prefer explicit subNavigationId prop + // 2. Fallback to component id + suffix + // 3. Default to fixed string (instead of random UUID) subNavigationId: props.subNavigationId ?? (props.id ? `${props.id}-sub-navigation` : 'sub-navigation'), navigationItemSafeTriangle: undefined, handleNavigationItemClick: (event: any) => {