API reference

SSRStyleCollector

stable
class SSRStyleCollector {
constructor();
collect<T>(fn: () => T): T;
getCss(): string;
getStyleTag(): string;
}
Updated 3 days agoEdit on GitHubWeb & native

Description

Per-request collector for server-side rendering. The renderer routes injected CSS to whichever collector is currently active rather than touching a non-existent document. Construct one per request, run the render through collect, and embed the result in <head>.

Concurrency note: the default active-collector pointer is module-level — safe for synchronous renderToString. For streaming SSR (renderToReadableStream) and React Server Components, import @usemotif/react/server once at app startup; that module registers an AsyncLocalStorage-backed storage backend.

Methods

MethodPurpose
collect<T>(fn): TRun fn with this collector active. CSS produced by motif components during the call is captured here instead of injected into the document. The previous active collector is restored on exit.
getCss(): stringRaw CSS captured during the collector's collect() call. Empty string if nothing was collected.
getStyleTag(): stringThe captured CSS wrapped in <style data-motif-ssr>. The data-motif-ssr marker is read on the client to seed the style-cache so the same rules are not injected twice after hydration.

CollectorContext

CollectorContext

stable
const CollectorContext: React.Context<SSRStyleCollector | null>

React context carrying the currently-active SSR collector. null means no active collector via context — the inject helpers fall back to the module-level storage backend (sync or AsyncLocalStorage).

App Router users wrap their layout in a registry that creates a collector via useState(() => new SSRStyleCollector()) and provides it through this context. Components read the collector via useActiveCollector and forward it as the override argument to injectAtRules / injectPseudoRules.

useActiveCollector

useActiveCollector

stable
function useActiveCollector(): SSRStyleCollector | null

Read the active collector from React context. Returns null when no collector provider is in scope.

Example: sync renderToString

example.tsx
import { renderToString } from 'react-dom/server';
import { SSRStyleCollector } from 'usemotif';
import { App } from './App';
 
const collector = new SSRStyleCollector();
const body = collector.collect(() => renderToString(<App />));
const styleTag = collector.getStyleTag();
 
const html = `<!doctype html>
<html><head>${styleTag}</head><body><div id="root">${body}</div></body></html>`;

Example: Next.js App Router registry

example.tsx
'use client';
import { useState, type ReactNode } from 'react';
import { useServerInsertedHTML } from 'next/navigation';
import { CollectorContext, SSRStyleCollector } from 'usemotif';
 
export function MotifStyleRegistry({ children }: { children: ReactNode }) {
const [collector] = useState(() => new SSRStyleCollector());
 
useServerInsertedHTML(() => {
  const css = collector.getCss();
  if (css.length === 0) return null;
  return <style data-motif-ssr dangerouslySetInnerHTML={{ __html: css }} />;
});
 
if (typeof window !== 'undefined') {
  return <>{children}</>;
}
 
return <CollectorContext.Provider value={collector}>{children}</CollectorContext.Provider>;
}
  • Server-side rendering — the integration guide for sync, streaming, and Next.js App Router.
  • Cross-platform — SSR is web-only; the native build does not ship these symbols.