Quick Answer: Use textContent for inline scripts and styles, innerHTML only when you need HTML entities. Example: script: [{ textContent: 'console.log("Hello")' }]
The <style>, <script> and <noscript> tags are unique in HTML as they can contain inner content that directly affects how your page behaves and appears. Unhead provides powerful utilities to manage this inner content safely and efficiently.
Unlike most other HTML tags which primarily use attributes, these special tags rely on their content to function. With Unhead, you can manipulate this content programmatically while benefiting from the library's deduplication and optimization features.
When working with the inner content of a tag, Unhead gives you two options for setting the content that appears between the opening and closing tags:
textContent: Treats the content as plain text, escaping any HTML charactersinnerHTML: Interprets the content as HTML, which allows for structured content but requires security considerationsThe choice between these properties depends on your specific needs and security requirements:
import { useHead } from '#imports'
// useHead: /docs/head/api/composables/use-head
useHead({
script: [
{
innerHTML: 'window.analytics = window.analytics || []',
},
],
style: [
{
textContent: 'body { background: salmon; color: cyan; }',
},
]
})
This example demonstrates adding:
Setting inner content using textContent is the safest approach for untrusted content. However, in some cases you might need to use innerHTML, particularly when working with rich content or third-party scripts that require HTML structure.
innerHTML, the content is not automatically sanitized. You must sanitize any user input or third-party content to prevent cross-site scripting (XSS) vulnerabilities that could compromise your application's security.For dealing with external content, consider:
import { useHead } from '#imports'
// Don't do this!
const someUserScript = await loadUserProvidedScript()
useHead({
script: [
{
// ❌ Dangerous - could contain malicious code!
innerHTML: someUserScript
},
],
})
import { useHead } from '#imports'
import DOMPurify from 'dompurify'
// Do this instead
const userProvidedContent = await loadUserProvidedContent()
useHead({
script: [
{
// ✅ Safe - content is sanitized
innerHTML: DOMPurify.sanitize(userProvidedContent)
},
],
})
For ease of use, Unhead provides a convenient shorthand syntax where you can simply provide a string as the array entry instead of an object with textContent or innerHTML.
import { useHead } from '#imports'
useHead({
script: [
'window.analytics = window.analytics || []',
],
style: [
'body { background: salmon; color: cyan; }',
]
})
Behind the scenes, Unhead automatically determines the appropriate property to use:
<style> tags: Content is applied as textContent (safer option)<script> and <noscript> tags: The appropriate property is selected based on contentWhen working with inner content for style and script tags, follow these best practices to ensure security, performance, and maintainability:
textContent over innerHTML whenever possible for security reasons.defer attribute for non-essential scriptsimport { useHead } from '#imports'
// Example of critical CSS with non-critical scripts
useHead({
style: [
// Critical CSS inline for faster rendering
'header, nav, .hero { /* Critical styles */ }',
],
script: [
{
src: '/assets/analytics.js',
defer: true, // Load after page rendering
}
]
})
src or hrefkey attributes to easily identify and update specific tagsimport { useHead } from '#imports'
useHead({
style: [
{
key: 'critical-css',
textContent: `
/* Only include truly critical styles here */
body { font-family: system-ui, sans-serif; }
.hero { height: 100vh; display: flex; align-items: center; }
`,
}
]
})
import { useHead } from '#imports'
const siteConfig = {
apiEndpoint: '/api/v1',
features: { darkMode: true, comments: false },
}
useHead({
script: [
{
id: 'site-config',
type: 'application/json',
textContent: JSON.stringify(siteConfig),
}
]
})
textContent for inline scripts and stylesinnerHTML only when you need HTML entities (prefer textContent)useScript() for complex script loading scenarios