Server rendering
The elements load in Node without a DOM, so pages rendered on the server can import them. Out of
the box, a framework’s server render sends the gui-* tags empty, and the elements fill in once
the browser upgrades them. The server-only @golemui/gui-components/ssr entry point renders their
content on the server too: labels, inputs and values arrive in the HTML, styled before any
JavaScript runs.
How it works
Section titled “How it works”- On the server, each element renders the same markup it renders in the browser, from the values your framework gives it. The rest of the page stays exactly as your framework rendered it.
- In the browser, nothing extra is needed. The server marks the content it rendered with
data-golemui-ssr, and each element replaces that content with its live render when it upgrades. Your framework hydrates the markup it rendered, as usual.
Set it up
Section titled “Set it up”Server rendering needs @lit-labs/ssr 4.1 or later, an optional peer dependency, in the project
that renders on the server. @golemui/gui-components/ssr, the entry point that renders the
elements, is server-only: it doesn’t load in the browser. Load
@golemui/gui-components/index.css at document level, so the server HTML is styled before any
JavaScript runs.
The setup for React, Next.js, Angular, Analog, Vue, Nuxt, Lit and Astro is in Installation.
What the server renders
Section titled “What the server renders”| Elements | On the server |
|---|---|
The fields, the pickers and gui-button | Their whole content: label, hint, control and value. |
The elements that wrap your markup: gui-tabs, gui-accordion, gui-alert and their parts | Your children, as your framework rendered them. The roles, the ARIA links and the hidden panels come when the element upgrades. |
gui-list and gui-multi-list, which render into a shadow root | Their items. The list renders around them when it upgrades. |
The live render in the browser generates the ids of each element’s parts again, and the element
keeps its own label, hint and errors linked. Set a uid only when something outside the element
points at those ids, such as your own aria-describedby, a CSS or test selector, or a link.
Limits
Section titled “Limits”- Vue, Nuxt and Astro read attributes only. A value bound as a property is missing from the
server HTML and shows once the element upgrades. In Vue and Nuxt, bind arrays and objects with
.propall the same, such as:options.prop="plans": Vue’s production hydration skips the other bindings of a custom element when their value is a constant. A select bound that way shows no options until it upgrades. React and Angular pass properties to the server render. - Wrapper elements upgrade in the browser. Until then, every tab panel shows and the tabs have
no roles. Put
hiddenon the inactive tab panels yourself to keep them out of sight in the server HTML:gui-tabsmanages that attribute once it upgrades. - Next.js development warning. The development server logs Lit’s “Multiple versions of Lit loaded” warning. Next.js bundles a page’s Server Components and Client Components apart, so the same version of Lit loads twice. Production builds don’t log it.
- Vue streaming.
renderElementsInHtmlworks on HTML, so it fitsrenderToString. WithrenderToWebStreamorrenderToNodeStream, either buffer the stream and pass the whole page, or pass each chunk as it comes. Vue sends a chunk at each async component boundary. An element whose start and end tags land in different chunks stays empty and renders in the browser. Nuxt hands the module the whole page, so it isn’t affected. - Render errors. An element that fails to render on the server logs a warning and stays empty, and the browser renders it as usual.