Head Tag Inner Content for Scripts, Styles, and JSON
Implementation overview
Configure inline content for script, style, noscript, and template tags with Unhead. This guide compares children, innerHTML, and textContent, including safe JSON serialization and XSS handling.
Use textContent or innerHTML to set inline content on script, style, and noscript entries. Neither property makes untrusted JavaScript, CSS, or HTML safe.
Inline content
import { useHead } from 'unhead'
useHead(unheadInstance, {
script: [
{ textContent: 'window.analytics = window.analytics || []' }
],
style: [
{ textContent: 'body { background: salmon; color: cyan; }' }
]
})
On the client, textContent is assigned through the DOM property while innerHTML is assigned through the corresponding HTML property. During SSR, both values are serialized as raw-element content. Unhead escapes closing script, style, and noscript sequences so the content cannot terminate its element early, but it does not sanitize the JavaScript, CSS, or HTML itself.
textContent and innerHTML as trusted-code APIs for scripts and styles. Safety depends on the parsing context: textContent is a safe sink for ordinary page text, but text inside <script> or <style> is still executable code. OWASP classifies direct script and style content as dangerous contexts, and MDN documents innerHTML as an HTML injection sink. HTML sanitizers do not make arbitrary JavaScript or CSS safe to execute.For a title, Unhead HTML-escapes the text during SSR. For JSON-like script types, it serializes object values and escapes < as \u003C.
String shorthand
A string entry is shorthand for innerHTML on script, style, and noscript tags:
import { useHead } from 'unhead'
useHead(unheadInstance, {
script: ['window.analytics = window.analytics || []'],
style: ['body { background: salmon; color: cyan; }']
})
Use the object form when you need attributes, a custom deduplication key, or an explicit content property.
JSON data
JSON-like script types accept an object in textContent or innerHTML. Unhead sets type="application/json" when an object is provided without a type.
import { useHead } from 'unhead'
useHead(unheadInstance, {
script: [
{
id: 'site-config',
type: 'application/json',
textContent: {
apiEndpoint: '/api/v1',
features: { darkMode: true, comments: false }
}
}
]
})
JSON-LD, import maps, and speculation rules receive the same JSON escaping during tag resolution.
JSON accepted by useHeadSafe
useHeadSafe() accepts JSON script content only when the script type ends in json. It parses and serializes the JSON again, removes prototype-pollution keys, and rejects invalid JSON. It removes executable scripts, inline style content, noscript content, and every innerHTML value.
External files
Use an external script or stylesheet when the content is large, cacheable, or maintained separately:
import { useHead } from 'unhead'
useHead(unheadInstance, {
link: [{ rel: 'stylesheet', href: '/assets/app.css' }],
script: [{ src: '/assets/analytics.js', defer: true }]
})
For loading triggers, API readiness, and callbacks, use useScript().
See Also
- Security: CSP and untrusted input overview
- Loading Scripts: Script management
- useHeadSafe() API: Restricted input handling
- useScript() API: Managed script loading
Class & Style Attributes
Add classes and styles to html and body tags with htmlAttrs and bodyAttrs. Support for strings, arrays, objects, and reactive values.
Tag Deduplication
Automatic tag deduplication by key, name, and property. Override layout tags in pages, manage verification tags, and customize merge strategies.