Environment: server, client.

Implemented by: vike-react/vike-vue/vike-solid.

You need vike-react/vike-vue/vike-solid to be able to use useConfig().

The useConfig() hook enables you to set configurations inside UI components, as well as inside Vike hooks such as +data.

We call it a universal hook: a hook that can be used in both UI components and Vike hooks. (Currently, useConfig() is the only universal hook.)

It currently supports following configs:

Inside +data

// pages/movies/+data.jsx
 
export { data }
 
import { useConfig } from 'vike-react/useConfig' // or vike-vue / vike-solid
 
async function data(pageContext) {
  const config = useConfig()
  const response = await fetch('https://star-wars.brillout.com/api/films.json')
  let { movies } = await response.json()
  config({
    title: `${movies.length} Star Wars Movies`
    Head: <meta name="description" content={`List of all ${movies.length} Star Wars movies.`} />
  })
  return { movies }
}

Make sure to call useConfig() before any await:

export async function data(pageContext) {
  const response = await fetch('https://star-wars.brillout.com/api/films.json')
  // ❌ Doesn't work: useConfig() has to be called before `await fetch()`
  const config = useConfig()
}

Inside components

import { useConfig } from 'vike-react/useConfig' // or vike-vue / vike-solid
 
function Movies() {
  // Fetch data
  const data = useSomeDataFetchingTool()
 
  // Set <head> tags
  const config = useConfig()
  config({
    title: data.title,
    Head: <meta property="og:image" content={data.previewImage} />
  })
 
  // Render UI
  return (
    <ul>
      { data.movies.map(({ title }) => (
        <li>{title}</li>
      )) }
    </ul>
  )
}

<Config> & <Head>

Inside components, you can also use <Config> and <Head>:

import { Config } from 'vike-react/Config' // or vike-vue / vike-solid
import { Head } from 'vike-react/Head' // or vike-vue / vike-solid
 
function Movies() {
  // Fetch data
  const data = useSomeDataFetchingTool()
 
  // Render UI and <head> tags
  return (
    <Config title={data.title} />
    <Head>
      <meta property="og:image" content={data.previewImage} />
    </Head>
    <ul>{
      data.movies.map(({ title }) => (
        <li>{title}</li>
      ))
    }</ul>
  )
}

Both achieve the same:

  • <Head><something/></Head>
  • <Config Head={<something/>}/>

There in't a <Title> component because it's expected to be a string: e.g. <Title><span>hello</span></Title> doesn't make sense.

Example: React Query

The useConfig() hook is particularly relevant when using integrations that enables components to fetch data such as vike-react-query and vike-react-apollo. Your components can then use the data they fetch to set <head> tags.

import { useConfig } from 'vike-react/useConfig'
import { useSuspenseQuery } from '@tanstack/react-query'
 
function Movies() {
  // Fetch data
  const query = useSuspenseQuery({
    queryKey: ['movies'],
    queryFn: () => fetch('https://star-wars.brillout.com/api/films.json')
  })
  const movies = query.data
 
  // Set <head> tags
  const config = useConfig()
  config({
    title: `${movies.length} Star Wars Movies` // <title>
    Head: <meta name="description" content={`List of all ${movies.length} Star Wars movies.`} />
  })
 
  // Render UI
  return (
    <ul>{
      movies.map(({ title }) => (
        <li>{title}</li>
      ))
    }</ul>
  )
}

Or with <Config> and <Head>:

import { Config } from 'vike-react/Config'
import { Head } from 'vike-react/Head'
import { useSuspenseQuery } from '@tanstack/react-query'
 
function Movies() {
  // Fetch data
  const query = useSuspenseQuery({
    queryKey: ['movies'],
    queryFn: () => fetch('https://star-wars.brillout.com/api/films.json')
  })
  const movies = query.data
 
  // Render UI and <head> tags
  return (
    <Config title={`${movies.length} Star Wars Movies`} />
    <Head>
      <meta name="description" content={`List of all ${movies.length} Star Wars movies.`} />
    </Head>
    <ul>{
      movies.map(({ title }) => (
        <li>{title}</li>
      ))
    }</ul>
  )
}

Serialization Error

You may get a serialization error while using useConfig().

Cannot serialize config set by useConfig()

The most common reason is because you're using useConfig() in a +data.js to modify a non-serializable config.

The workaround is to define +data.shared.js instead of +data.js.

// pages/some-page/+data.js
// pages/some-page/+data.shared.js
 
import { useConfig } from 'vike-react/useConfig' // or vike-vue / vike-solid
 
export async function data (pageContext) {
  const config = useConfig()
  // ...
}

The issue here is that defining the data() hook inside a +data.js file means that it's always called on the server-side, even upon client-side page navigation. Consequently, upon client-side page navigation, the data fetched on the server-side needs to be serialized and passed to the client-side.