--- title: Inline Style & Scripts description: Learn how to safely add inline styles and scripts using Unhead's inner content features. --- ## Introduction The `<style>`{lang="html"}, `<script>`{lang="html"} and `<noscript>`{lang="html"} 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. ## Inner Content Options 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`{lang="bash"}: Treats the content as plain text, escaping any HTML characters - `innerHTML`{lang="bash"}: Interprets the content as HTML, which allows for structured content but requires security considerations The choice between these properties depends on your specific needs and security requirements: ```ts import { useHead } from '@unhead/dynamic-import' useHead({ script: [ { innerHTML: 'window.analytics = window.analytics || []', }, ], style: [ { textContent: 'body { background: salmon; color: cyan; }', }, ] }) ``` This example demonstrates adding: 1. An inline script that initializes an analytics array 2. An inline style that sets background and text colors ### Security Considerations with `innerHTML` Setting inner content using `textContent`{lang="bash"} is the safest approach for untrusted content. However, in some cases you might need to use `innerHTML`{lang="ts"}, particularly when working with rich content or third-party scripts that require HTML structure. ::warning When using `innerHTML`{lang="bash"}, 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: - Using a sanitization library like DOMPurify - Applying framework-specific sanitization utilities - Using the [useHeadSafe()](/docs/head/api/composables/use-head-safe) composable instead #### Example of Unsafe Usage ```ts import { useHead } from '@unhead/dynamic-import' // Don't do this! const someUserScript = await loadUserProvidedScript() useHead({ script: [ { // ❌ Dangerous - could contain malicious code! innerHTML: someUserScript }, ], }) ``` #### Example of Safe Usage ```ts import { useHead } from '@unhead/dynamic-import' import DOMPurify from 'dompurify' // Do this instead const userProvidedContent = await loadUserProvidedContent() useHead({ script: [ { // ✅ Safe - content is sanitized innerHTML: DOMPurify.sanitize(userProvidedContent) }, ], }) ``` ## Shorthand String Syntax 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`{lang="ts"} or `innerHTML`{lang="ts"}. ```ts import { useHead } from '@unhead/dynamic-import' useHead({ script: [ 'window.analytics = window.analytics || []', ], style: [ 'body { background: salmon; color: cyan; }', ] }) ``` ### How It Works Behind the scenes, Unhead automatically determines the appropriate property to use: - For `<style>`{lang="html"} tags: Content is applied as `textContent`{lang="ts"} (safer option) - For `<script>`{lang="html"} and `<noscript>`{lang="html"} tags: The appropriate property is selected based on content ::tip The shorthand syntax is ideal for simple, static content where you want cleaner code with fewer lines. :: ## Best Practices When working with inner content for style and script tags, follow these best practices to ensure security, performance, and maintainability: ### Security ::tip Always prefer `textContent`{lang="ts"} over `innerHTML`{lang="ts"} whenever possible for security reasons. :: - **Sanitize All External Content**: Always sanitize any user-generated or third-party content - **Consider useHeadSafe**: For untrusted content, prefer the [useHeadSafe()](/docs/head/api/composables/use-head-safe) composable - **Validate Input**: Check content before including it in your head tags ### Performance - **Balance Inline vs. External**: While inline scripts and styles eliminate network requests, they can increase HTML size - **Use Critical CSS**: For critical above-the-fold styles, inline CSS can improve perceived performance - **Defer Non-Critical Scripts**: Use the `defer` attribute for non-essential scripts ```ts import { useHead } from '@unhead/dynamic-import' // 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 } ] }) ``` ### Maintainability - **Keep It Simple**: For complex scripts or styles, use external files with `src` or `href` - **Use Keys**: Add `key` attributes to easily identify and update specific tags - **Consider the Alternatives**: - For scripts, use the dedicated [useScript()](/docs/head/api/composables/use-script) composable - For complex styling needs, use external stylesheets ## Common Use Cases ### Critical CSS ```ts import { useHead } from '@unhead/dynamic-import' 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; } `, } ] }) ``` ### Inline JSON Configuration ```ts import { useHead } from '@unhead/dynamic-import' const siteConfig = { apiEndpoint: '/api/v1', features: { darkMode: true, comments: false }, } useHead({ script: [ { id: 'site-config', type: 'application/json', textContent: JSON.stringify(siteConfig), } ] }) ```