Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions src/internal/portal/__tests__/portal.ssr.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* @jest-environment node
*/
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import React from 'react';
import { renderToStaticMarkup } from 'react-dom/server';

import Portal from '../index';

// The probe span must be part of the server markup, otherwise it appears as an
// added element during hydration and React discards the whole subtree.
// See https://github.com/cloudscape-design/component-toolkit/pull/214
test('renders the probe span so that server and client markup match', () => {
const content = renderToStaticMarkup(
<Portal>
<p>Hello!</p>
</Portal>
);
expect(content).toBe('<span style="display:none"></span>');
});

test('does not render portal children on the server', () => {
const content = renderToStaticMarkup(
<Portal>
<p>Hello!</p>
</Portal>
);
expect(content).not.toContain('Hello!');
});
5 changes: 3 additions & 2 deletions src/internal/portal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,9 @@ export default function Portal({
// On the first render, activeContainer is null because the layout effect hasn't
// created it yet. We render a hidden probe span so the effect can read
// ref.current.ownerDocument to discover the correct document (e.g. inside iframes).
// In SSR there's no document, so we return null to match the previous behavior.
if (!activeContainer && typeof document !== 'undefined') {
// The span is rendered during SSR too, so that the server markup matches the first
// client render and hydration does not fail.
if (!activeContainer) {
return <span ref={ref} style={{ display: 'none' }} />;
}

Expand Down
Loading