Index of every page on this site: llms.txt
Solid.js
Get Started

Installing Unhead with Solid.js

Install @unhead/solid-js, wrap the application with UnheadContext.Provider, and call useHead() in components.

The adapter uses Solid context for the head instance and exposes hooks for head tags, SEO metadata, and scripts. The examples follow Vite's SSR structure; SPAs use the same client entry.

Install Unhead

1. Add Dependency

Install the @unhead/solid-js dependency in your project.

bash
pnpm add @unhead/solid-js

2. Set Up Client-Side Rendering

Create the browser instance from @unhead/solid-js/client. In a Vite SSR app this usually belongs in entry-client.ts; in an SPA, put it in the main entry.

src/entry-client.ts
import { createHead, UnheadContext } from '@unhead/solid-js/client'
import { hydrate } from 'solid-js/web'
import App from './App'
/* @refresh reload */
import './index.css'

hydrate(() => {
  const head = createHead()
  return (<UnheadContext.Provider value={head}><App /></UnheadContext.Provider>)
}, document.getElementById('root'))

3. Set Up Server-Side Rendering

Serving your app as an SPA? You can skip this step. See the SPA guide for template defaults, crawler limits, and route prerendering.

For SSR, create a fresh instance from @unhead/solid-js/server for each request and return it with the rendered app.

src/entry-server.ts
import { createHead, UnheadContext } from '@unhead/solid-js/server'
import { renderToString } from 'solid-js/web'
import App from './App'

export function render(_url: string) {
  const unhead = createHead()
  const html = renderToString(() => <UnheadContext.Provider value={unhead}><App /></UnheadContext.Provider>)
  return { html, unhead }
}

After Solid renders, pass the instance and complete HTML template to transformHtmlTemplate():

server.ts
import { transformHtmlTemplate } from '@unhead/solid-js/server'
// ...

// Serve HTML
app.use('*', async (req, res) => {
  try {
    // ...

    const rendered = await render(url)

    const html = transformHtmlTemplate(
      rendered.unhead,
      template
        .replace(`<!--app-head-->`, generateHydrationScript())
        .replace(`<!--app-html-->`, rendered.html ?? '')
    )

    res.status(200).set({ 'Content-Type': 'text/html' }).send(html)
  }
  catch (e) {
    // ...
  }
})
// ...

4. Add Head Tags

The server head inserts three defaults:

  • <meta charset="utf-8">
  • <meta name="viewport" content="width=device-width, initial-scale=1">
  • <html lang="en">

Set server-only defaults through init. Keeping them in the server entry also keeps them out of the client bundle.

src/entry-server.ts
import { createHead, UnheadContext } from '@unhead/solid-js/server'
import { renderToString } from 'solid-js/web'
import App from './App'

export function render(_url: string) {
  const unhead = createHead({
    // change default initial lang
    init: [
      {
        htmlAttrs: { lang: 'en' },
        title: 'Default title',
        titleTemplate: '%s - My Site',
      },
    ]
  })
  const html = renderToString(() => <UnheadContext.Provider value={unhead}><App /></UnheadContext.Provider>)
  return { html, unhead }
}

Call useHead() inside a component to add tags:

App.tsx
import { useHead } from '@unhead/solid-js'

export default function App() {
  useHead({
    title: 'Example Site',
    meta: [
      { name: 'description', content: 'An example page description.' }
    ]
  })

  return (
    <div>
      <h1>Hello World</h1>
    </div>
  )
}

Next Steps

Hooks:

Optional integrations:

Did this page help you?