Svelte
Core Concepts

Inline Style & Scripts

Introduction

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.

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: Treats the content as plain text, escaping any HTML characters
  • innerHTML: 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:

import { useHead } from '@unhead/svelte'

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 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.

When using 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:

  • Using a sanitization library like DOMPurify
  • Applying framework-specific sanitization utilities
  • Using the useHeadSafe() composable instead

Example of Unsafe Usage

import { useHead } from '@unhead/svelte'

// Don't do this!
const someUserScript = await loadUserProvidedScript()
useHead({
  script: [
    {
      // ❌ Dangerous - could contain malicious code!
      innerHTML: someUserScript
    },
  ],
})

Example of Safe Usage

import { useHead } from '@unhead/svelte'
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 or innerHTML.

import { useHead } from '@unhead/svelte'

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> tags: Content is applied as textContent (safer option)
  • For <script> and <noscript> tags: The appropriate property is selected based on content
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

Always prefer textContent over innerHTML 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() 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
import { useHead } from '@unhead/svelte'

// 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() composable
    • For complex styling needs, use external stylesheets

Common Use Cases

Critical CSS

import { useHead } from '@unhead/svelte'

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

import { useHead } from '@unhead/svelte'

const siteConfig = {
  apiEndpoint: '/api/v1',
  features: { darkMode: true, comments: false },
}

useHead({
  script: [
    {
      id: 'site-config',
      type: 'application/json',
      textContent: JSON.stringify(siteConfig),
    }
  ]
})
Did this page help you?