Skip to content
Nizivo UI

ThemeScript

Sets page-level attributes before first paint, so nothing changes once the page has painted: the reader's saved theme (data-nz-theme from localStorage key nz-theme: light, dark or system) and data-nz-platform (apple or other). The rules are on themeScript. Render it in <head> (<head><ThemeScript nonce={nonce} /></head> in a root layout), put the app's default theme on <html> (data-nz-theme="system", or none for light), and put suppressHydrationWarning on <html>, whose attributes the script changes.

Server component, no client JS

Import

import { ThemeScript } from '@nizivo/react/theme-script';

Static or interactive

Server. It is no client module and hydrates nothing: it renders one inline <script> (379 bytes) that runs in <head> before the body is parsed. How to choose.

In a client app (a Vite or React Router single-page app, or a 'use client' file) it is an ordinary React component: event handlers, refs and state work as usual. In a client app.

Examples

Basic

In a root layout, ThemeScript goes in <head>; here it runs where it is rendered. It restores the reader's saved theme (localStorage key nz-theme) and marks the page data-nz-platform="apple" on Apple devices, so the shortcut below reads ⌘K there and Ctrl+K elsewhere.

Search with ⌘KCtrl+K.

import type { JSX } from 'react';
import { Kbd } from '@nizivo/react/kbd';
import { ThemeScript } from '@nizivo/react/theme-script';

export function ThemeScriptExample(): JSX.Element {
  return (
    <p>
      <ThemeScript />
      Search with <Kbd keys="mod+k" />.
    </p>
  );
}

Props

Sets page-level attributes before first paint, so nothing changes once the page has painted: the reader's saved theme (data-nz-theme from localStorage key nz-theme: light, dark or system) and data-nz-platform (apple or other). The rules are on themeScript. Render it in <head> (<head><ThemeScript nonce={nonce} /></head> in a root layout), put the app's default theme on <html> (data-nz-theme="system", or none for light), and put suppressHydrationWarning on <html>, whose attributes the script changes.

Server component Renders no element of its own. Props: ThemeScriptProps. Source: src/theme-script/theme-script.tsx.

NameTypeDefaultDescription
noncestring–

The CSP nonce for the inline script (script-src 'nonce-…'). Not needed with a hash allowlist.

Other exports

ThemeScriptProps type

import type { ThemeScriptProps } from '@nizivo/react/theme-script'

The props of ThemeScript, listed above.

themeScript constant

import { themeScript } from '@nizivo/react/theme-script'

The script ThemeScript renders, for frameworks that inline it themselves (Astro: <script is:inline set:html={themeScript} />; Vite: a transformIndexHtml tag) or that allow it by hash under a strict CSP. It runs in <head>, before <body> exists, and sets two attributes on <html>:

- data-nz-theme, the reader's saved theme. It reads localStorage key nz-theme; when the value is "light", "dark" or "system", it sets data-nz-theme to that value, replacing what the server rendered (the server's value is the app's default; the stored one is the reader's choice). "system" is set as is, not resolved: CSS follows the operating system from it, live, with no listener. With nothing stored, any other value, or storage blocked (a sandboxed frame, disabled site data), the attribute is left as the server rendered it. A theme switch saves the choice with localStorage.setItem('nz-theme', value) and sets the attribute itself. - data-nz-platform: "apple" when the platform string matches /mac|iphone|ipad|ipod/i, else "other". The platform string is navigator.userAgentData.platform where the browser has it (Chromium: "macOS", "Windows", …), else navigator.platform ("MacIntel", "iPhone", "iPad"; iPadOS reports "MacIntel", which is still Apple). It never reads the user-agent string. A value already on <html> (set by the server, or by a test) is kept. Kbd reads the attribute to show ⌘K or Ctrl+K.

Each half runs in its own try, so blocked storage never stops the platform half, and the script never throws into the page.

Under a strict CSP, allow it by hash: script-src 'sha256-nA1HUQWDdDUFqqoxWbjzCzcYSjzWLEe0pwDdRCMGqOw='. The hash changes only when the script does, and a change is called out in the changelog.

const themeScript: string

Data attributes and slots

Style parts by class (.nz-<slot>) and state by data attribute. Attribute meanings come from contracts/vocabulary.json.

This entry renders no element with a data-slot.

Accessibility

Nothing in this component takes focus or keyboard input.

Keyboard

None.

Figma

Node ids from design/component-map.json, which nz gen writes from component.json. The links open the Nizivo Figma library, which may ask you to sign in.

  • Canonical: none
  • Ghost masters: none

On this page