Server-side rendering

The server-side rendering support of the Helsinki Design System makes the user's landing experience to pages smooth without flashes of unstyled content.

What is server-side rendering?

Server-side rendering (SSR) is the process where the rendering of HTML pages is done on the server-side. The fully rendered HTML document is then sent to the browser. The rendering of the HTML can happen at build time (Static site generation or pre-rendering), or during an HTTP request. The alternative to SSR is client-side rendering (CSR), where most of the HTML content is composed and rendered in the browser using JavaScript.

How does HDS support server-side rendering?

For HDS components to work with server-side rendering, you need to inject the critical CSS styles of the HDS components that are being used into the initially rendered HTML on the server's side. For hds-core, you must include the styles from the provided CSS files yourself. For hds-react HDS provides multiple options, which we will cover next.

Critical CSS
Critical CSS is applied to above-the-fold elements. It provides the styles for the immediately visible content in the browser viewport when the user opens your website. Critical CSS does not usually have the styles of the elements that are in the scrollable content outside of the browser viewport. There is one exception though, and that is if you have anchor links on the page. When user opens website from an URL that includes an anchor link, the browser automatically scrolls the page so that the link will be visible.

HDS React components use CSS-in-JS in a way where the styles are by default injected into the head tag in the browser. If you use server-side rendering and do not include the critical styles on the server, this leads to flashes of unstyled content when the user lands on the page.

To include critical styles on the server, HDS exposes a tool for extracting the used critical styles of HDS components. This should come in handy in multiple ways:

  • Automatically extracts styles based on used HTML.
  • If you add more HDS components later, you do not need to remember to add their styles separately.
  • If you happen to remove HDS components, you do not need to remember to remove their respective styles.

Let's go through a simple example of the usage of the tool:

import { getCriticalHdsRules, hdsStyles } from "hds-react";
const criticalHdsRules = await getCriticalHdsRules(bodyHTML, hdsStyles);
const finalHTML =
<html>
<head>
...
<style data-used-styles dangerouslySetInnerHTML={{ __html: criticalHdsRules }} />
</head>
<body>
...
</body>
<html>

First, we import the tool that is named getCriticalHdsRules. To be able to call it, we need two things:

  1. The initially to-be-rendered HTML body code as a string.
  2. hdsStyles - a variable holding all the styles of the HDS react components as a string.

Calling it returns a string containing the critical CSS styles. The rest is easy, we set those styles into a style tag, that we will then inject into the finally rendered HTML document. It can be wise to cache the result of getCriticalHdsRules based on the function parameters in order to improve performance.

See below for more complete examples:

HDS react provides all the styles of HDS components in a file called index.css, located at the root of the library. You can import that file and collect the critical CSS styles from there. Another alternative is to use exported variable called hdsStyles:

import { hdsStyles } from 'hds-react';

This variable holds all the styles of HDS React components compiled into a single string. It might be tempting to include all the styles in hdsStyles or index.css to your HTML, and call it a day. This is not optimal because the size of the HDS styles is large and probably growing as new components are added to it. Adding all the styles might have an impact on the performance of the app. Instead, you should collect only the necessary styles for the initial render. We recommend using the tool described in option 1. But if you are unable to use that, extracting the critical CSS styles from either hdsStyles or index.css might work out for you.

Customising HDS components and server-side rendering

If you customise hds-react components with the theme prop, the style changes will not be visible on the first render. The preferred way to customise hds-react components with server-side rendering is using the className prop. However, notice that sometimes CSS selector specificity of 0-1-0 may not be enough to overwrite default CSS variables. This depends on the CSS declaration order on the page or component's default styles selector specificity. You may have to use a more specific CSS selector for the custom styles class, for example, #myComponent.custom-class, .custom-class.custom-class, etc.