Quick Answer: In Solid, use signals with useHead() inside createEffect(). Pass getter functions for reactive values. Head tags update automatically with signal changes.
Unhead integrates seamlessly with Solid.js's fine-grained reactivity system. This guide explains how to effectively manage reactive head tags in your Solid.js applications.
Unhead for Solid.js leverages Solid's reactive primitives including signals, effects, and contexts to provide a reactive head management solution. When your application state changes, Solid.js's reactivity system automatically ensures your head tags reflect the current state.
Unhead uses Solid.js's Context API to provide head management throughout your component tree:
import { createHead, UnheadContext } from '@unhead/solid-js/client'
import { render } from 'solid-js/web'
import App from './App'
const head = createHead()
render(() => (
<UnheadContext.Provider value={head}>
<App />
</UnheadContext.Provider>
), document.getElementById('root'))
This pattern keeps head state contained and manageable, making components more testable and preventing hydration issues.
Solid.js's signals work naturally with Unhead. When you pass signals to useHead(), the head tags update whenever the signal values change:
import { useHead } from '@unhead/solid-js'
import { createSignal } from 'solid-js'
function PageHead() {
const [title, setTitle] = createSignal('Welcome to My App')
// Head tags will update when title signal changes
useHead(() => ({
title: title()
}))
return (
<button onClick={() => setTitle('Updated Title')}>
Update Title
</button>
)
}
You can also pass signals directly to useHead():
import { useHead } from '@unhead/solid-js'
import { createSignal } from 'solid-js'
function PageHead() {
const [title, setTitle] = createSignal('Welcome to My App')
const [description, setDescription] = createSignal('My site description')
useHead({
get title() { return title() },
meta: [
{
name: 'description',
get content() { return description() }
}
]
})
return (
<>
<button onClick={() => setTitle('Updated Title')}>Update Title</button>
<button onClick={() => setDescription('New description')}>Update Description</button>
</>
)
}
It's common to update head tags based on asynchronous data:
import { useHead } from '@unhead/solid-js'
import { createResource, createSignal } from 'solid-js'
async function fetchPageData(id) {
const response = await fetch(`/api/page/${id}`)
return response.json()
}
function PageHead({ id }) {
const [pageData] = createResource(() => id, fetchPageData)
useHead(() => ({
title: pageData()?.title || 'Loading...',
meta: [
{
name: 'description',
content: pageData()?.description || 'Loading page content...'
}
]
}))
return null
}
For pages with multiple meta tags, you can manage them together with Solid.js's reactive primitives:
import { useHead } from '@unhead/solid-js'
import { createResource } from 'solid-js'
async function fetchProduct(id) {
const response = await fetch(`/api/products/${id}`)
return response.json()
}
function ProductHead({ id }) {
const [product] = createResource(() => id, fetchProduct)
useHead(() => ({
title: product()?.title || 'Loading Product...',
meta: [
{ name: 'description', content: product()?.description || '' },
{ property: 'og:image', content: product()?.image || '/placeholder.jpg' },
{ property: 'product:price', content: product()?.price || '' }
]
}))
return null
}
Solid.js's composable nature makes it easy to create reusable head components:
import { useHead } from '@unhead/solid-js'
import { mergeProps } from 'solid-js'
function SEOHead(props) {
const merged = mergeProps({
title: 'Default Title',
description: 'Default description',
ogImage: '/default-og.jpg'
}, props)
useHead(() => ({
title: merged.title,
meta: [
{ name: 'description', content: merged.description },
{ property: 'og:title', content: merged.title },
{ property: 'og:description', content: merged.description },
{ property: 'og:image', content: merged.ogImage }
]
}))
return null
}
// Usage
function HomePage() {
return (
<div>
<SEOHead
title="Home Page"
description="Welcome to our website"
/>
{/* Page content */}
</div>
)
}
You can leverage Solid.js's control flow primitives to conditionally render head tags:
import { useHead } from '@unhead/solid-js'
import { createEffect, createSignal, Show } from 'solid-js'
function DynamicHead() {
const [isLoggedIn, setIsLoggedIn] = createSignal(false)
const [user, setUser] = createSignal(null)
// Simulate login
const login = () => {
setUser({ name: 'John Doe', id: '123' })
setIsLoggedIn(true)
}
createEffect(() => {
if (isLoggedIn()) {
useHead({
title: `Dashboard - ${user().name}`,
meta: [
{ name: 'description', content: 'Your personal dashboard' }
]
})
}
else {
useHead({
title: 'Login',
meta: [
{ name: 'description', content: 'Login to access your dashboard' },
{ name: 'robots', content: 'noindex' }
]
})
}
})
return (
<div>
<Show when={isLoggedIn()} fallback={<button onClick={login}>Login</button>}>
<h1>
Welcome,
{user().name}
!
</h1>
</Show>
</div>
)
}
Under the hood, Unhead in Solid.js:
createEffectonCleanup when components are disposedThe implementation wraps head entries with Solid.js's reactive primitives that:
function ProductPage(props) {
return (
<>
<GlobalHead />
<ProductHead id={props.id} />
<ProductSchema id={props.id} />
{/* UI components */}
</>
)
}