SSR Considerations
Imperative Surface uses window, document, document.body, and createRoot() when a surface is presented.
The presentation APIs are therefore browser-only.
Do not present during render
Avoid:
// Incorrect
const result = Surface.Dialog.present(...);during server rendering or component render.
Instead, call it from a client event handler, effect, or another browser-only interaction:
'use client';
async function openDialog() {
const result = await Surface.Dialog.present({
body: MyDialog,
});
}What happens on the server?
The implementation checks:
if (typeof window === 'undefined') {
return reject('Window not available');
}This means a server-side call rejects rather than attempting to access the DOM.
Recommended Next.js architecture
Keep the page and data loading on the server when useful, then isolate interactive surface triggers into client components.
// Server component
export default async function Page() {
const data = await getData();
return <InteractiveActions data={data} />;
}// Client component
'use client';
export function InteractiveActions({ data }) {
// Surface.Dialog.present(...)
}