Server-side rendering
Sveltier is safe to render on the server and paints the right theme from the first frame, before any JavaScript runs.
How the theme avoids a flash
- One stylesheet for every theme. The root provider writes a
<style>into<head>with one rule per theme, keyed bydata-sv-theme. - "System" is pure CSS. It maps to the light or dark theme with
prefers-color-schememedia rules, so no script is needed to follow the operating system. - A remembered choice is restored before the body is parsed. A tiny inline
script copies it from
localStorageonto<html>. Only known theme names are accepted. - Hydration never repaints. The provider reads the stored choice after mount, so the first client render matches the server HTML and the colours never change.
This is tested in Chromium, Firefox and WebKit by sampling every animation frame from document creation through hydration.
SSR safety
No module touches window or document at import time, and every component
has a server rendering test that runs in Node.
Letting the server know the choice
The provider remembers choices in localStorage, which the server cannot read. If
your server should render theme-dependent markup (for example a toggle that shows the current
mode), keep the choice in a cookie and pass it as theme:
<!-- src/routes/+layout.svelte -->
<script>
import { UIProvider } from 'sveltier';
import { monolith } from 'sveltier/themes/monolith';
let { data, children } = $props();
let theme = $state(data.theme ?? 'system');
// Mirror the choice into a cookie so the server can render it next time.
$effect(() => {
document.cookie = `theme=${theme}; path=/; max-age=31536000; samesite=lax`;
});
</script>
<UIProvider themes={monolith} bind:theme storageKey={false}>
{@render children()}
</UIProvider>
// src/routes/+layout.server.ts
export const load = ({ cookies }) => ({ theme: cookies.get('theme') });Content Security Policy
The provider writes one inline <style> and, when persistence is on, one
inline <script>. Pass your per-request nonce, or allow the script by hash:
<UIProvider themes={monolith} nonce={data.cspNonce}>…</UIProvider>
// or allow the restore script by hash
import { themeScript, monolith } from 'sveltier';
const script = themeScript('sv-theme', ['system', ...Object.keys(monolith)]);
// sha256 of `script` goes into script-srcSet storageKey={false} to drop the script entirely.