Head tags — title, meta, link, script, style — are emitted by FaceTheory in a stable order so that server-rendered HTML and client-hydrated DOM match exactly. Reaching around the head primitive to inject tags directly into a component body breaks the determinism guarantee.
The head primitive
FaceTheory exposes three head helpers from the main entry:
import {
renderFaceHead,
normalizeHeadTags,
renderHeadTag,
type FaceHeadTag,
} from '@theory-cloud/facetheory';
renderFaceHead(out, options)— render the head section from aFaceRenderResult. Accepts an optionalcspNonceandallowedOrigin.normalizeHeadTags(tags, options)— canonicalize an array of head tags (de-duplicate, apply nonces).renderHeadTag(tag)— serialize a single tag to HTML.
FaceHeadTag shape
type FaceHeadTag =
| { type: 'title'; text: string }
| { type: 'meta'; attrs: FaceAttributes }
| { type: 'link'; attrs: FaceAttributes }
| { type: 'script'; attrs: FaceAttributes; body?: string }
| { type: 'style'; cssText: string; attrs?: FaceAttributes }
| { type: 'raw'; html: string };
Faces declare head tags through FaceRenderResult.headTags:
return {
html: '<h1>Hello</h1>',
headTags: [
{ type: 'title', text: 'Hello FaceTheory' },
{ type: 'meta', attrs: { name: 'description', content: 'A FaceTheory page' } },
{ type: 'link', attrs: { rel: 'stylesheet', href: '/assets/app.css' } },
],
};
The raw escape hatch
{ type: 'raw', html } inserts HTML verbatim into <head> without escaping or nonce augmentation. Use it only when the caller fully owns the HTML, and never for content that could carry user input. Strict CSP rules disable this path — see Strict CSP.
Structured <style> vs raw HTML
Prefer structured styleTags (which take cssText + optional attrs) over { type: 'raw' } for <style> injection. The structured path lets FaceTheory’s deterministic emission and CSP enforcement apply consistently. See Core Patterns → Emit custom head styles through structured tags.
CSS-in-JS extraction
For React + Emotion, the React adapter wires @emotion/server automatically when you use createReactStreamFace with Emotion-aware components. The extracted CSS is emitted as deterministic <style> tags. For Vue and Svelte, framework-native style emission (Vue scoped styles, Svelte compile-time CSS) flows through the same head primitive.