The useScript composable provides an enhanced developer experience for loading third-party scripts with intelligent defaults for performance, security, and lifecycle management.
Quick Start:
const { proxy, onLoaded } = useScript('https://example.com/analytics.js')
// Call functions immediately (queued until loaded)
proxy.track('pageview')
// Or wait for script to load
onLoaded(() => {
console.log('Script ready!')
})
import { useScript } from '@unhead/solid-js'
const { onLoaded } = useScript('https://example.com/script.js')
onLoaded(() => {
// Script loaded successfully
console.log('Script is ready to use')
})
A singleton pattern is implemented so scripts with the same src or key are only loaded once globally. This helps prevent duplicate script loading and ensures consistent initialization.
The following defaults are applied for optimal performance and security:
defer enabled for proper execution orderfetchpriority="low" to prioritize critical resourcescrossorigin="anonymous" prevents cookie accessreferrerpolicy="no-referrer" blocks referrer headersPass a URL string for the quickest implementation:
import { useScript } from '@unhead/solid-js'
useScript('https://example.com/script.js')
Pass an options object to customize any <script> attribute:
import { useScript } from '@unhead/solid-js'
useScript({
src: 'https://example.com/script.js',
id: 'my-script',
async: true,
defer: false,
crossorigin: false, // disable crossorigin='anonymous'
// Any valid script attribute can be used
})
Fine-tune when and how scripts load with the second parameter:
import { useScript } from '@unhead/solid-js'
useScript('https://example.com/script.js', {
// When to load the script
trigger: 'client', // | 'server' | Promise | ((load) => void)
// Resource hint strategy
warmupStrategy: 'preload', // | 'prefetch' | 'preconnect' | 'dns-prefetch',
// Access the script's API
use: () => window.externalAPI
})
Control precisely when scripts load with different trigger strategies:
import { useScript } from '@unhead/solid-js'
// Load immediately on the client (default)
useScript(src, { trigger: 'client' })
// Load during server rendering
useScript(src, { trigger: 'server' })
// Load when a promise resolves
useScript(src, {
trigger: new Promise(resolve =>
setTimeout(resolve, 3000)
)
})
// Custom load function
useScript(src, {
trigger: (load) => {
document.getElementById('load-button').addEventListener('click', load)
}
})
The script passes through these lifecycle states:
awaitingLoad - Initial stateloading - Script is loadingloaded - Script loaded successfullyerror - Script failed to loadremoved - Script was removedMonitor these states with lifecycle hooks:
import { useScript } from '@unhead/solid-js'
const script = useScript('https://example.com/script.js')
script.onLoaded((api) => {
// Script loaded successfully
console.log('Script is ready')
})
script.onError(() => {
// Script failed to load
console.error('Script loading failed')
})
The warmupStrategy option automatically adds resource hints to optimize loading:
import { useScript } from '@unhead/solid-js'
useScript('https://example.com/script.js', {
// Preload - highest priority, load ASAP
warmupStrategy: 'preload',
// Prefetch - load when browser is idle
warmupStrategy: 'prefetch',
// Preconnect - setup connection early
warmupStrategy: 'preconnect',
// DNS Prefetch - resolve DNS early
warmupStrategy: 'dns-prefetch'
})
preload for essential scripts needed soon after page loadprefetch for scripts needed later in the user journeypreconnect or dns-prefetch to optimize third-party domainsIf you need to access the script's API before it loads, use the use option with proxy support:
import { useScript } from '@unhead/solid-js'
const script = useScript({
src: 'https://maps.googleapis.com/maps/api/js'
}, {
use: () => window.google.maps
})
// Works before script loads!
const map = script.proxy.Map()
The proxy records all calls and replays them once the script is loaded, allowing you to use the API immediately in your code without worrying about loading state.
import { useScript } from '@unhead/solid-js'
useScript({
src: 'https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX',
async: true
}, {
trigger: 'client'
})
// Initialize gtag
useHead({
script: [
{
children: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX');
`,
key: 'gtag-config'
}
]
})
import { useScript } from '@unhead/solid-js'
// Load YouTube player only when user clicks play
useScript('https://www.youtube.com/iframe_api', {
trigger: (load) => {
document.getElementById('play-video').addEventListener('click', () => {
load()
// Show loading indicator while script is loading
})
}
})
src: String URL or object with script attributestrigger: When to load the script ('client', 'server', Promise, or custom function)warmupStrategy: Resource hint strategy ('preload', 'prefetch', 'preconnect', 'dns-prefetch')use: Function to access the script's APIReturns a script controller object with these properties:
status: Current lifecycle stateonLoaded: Register callback for successful loadonError: Register callback for loading failureproxy: Proxy to the script's API (if use option provided)Use the trigger option with a custom function and call load():
const { load } = useScript('heavy-library.js', {
trigger: (load) => {
button.onclick = () => load()
}
})
The proxy queues calls until the script loads, making your code resilient to loading delays and adblockers.