You can use useConfig() inside any Vike hook, most notably +data.
// pages/movies/+data.jsximport { useConfig } from 'vike-react/useConfig' // or vike-{vue,solid}export 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()}
Normally hooks can only be used inside UI components — useConfig() is different: it can also be used inside Vike hooks. We call it a universal hook (useConfig() is the only universal hook so far).
UI components
You can also use useConfig() inside UI components.
// pages/product/@id/+Page.jsximport { useConfig } from 'vike-react/useConfig' // or vike-{vue,solid}import { useData } from 'vike-react/useData' // or vike-{vue,solid}export function Page() { const config = useConfig() const data = useData() // Set <head> tags config({ title: data.product.name, // Image shown when sharing on social sites (Twitter, WhatsApp, ...) Head: <meta property="og:image" content={data.product.image} /> }) // Render UI return <> <h1>{data.product.name}</h1> <p>{data.product.description}</p> </>}
For Vue you can use the following:
import { h } from 'vue'config({ Head: h('meta', { property: 'og:image', content: data.product.image })})
Likewise, <Head><something/></Head> and <Config Head={<something/>}/> are equivalent as well.
Unlike other frameworks, Vike doesn't implement a <Title> component because its value must be a string — <Title><b>Hello</b> World</Title> doesn't make sense.
Example: React Query
The useConfig() hook is especially useful when using extensions such as
vike-react-query
and
vike-react-apollo
that enable components to fetch data.
It enables your components to 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> )}
The <meta name="description"> tag is only shown to bots. See the explanation in the section below HTML Streaming.
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> )}
This happens when a component calls useConfig() after the HTML stream has already started and the whole <head> block has already been sent to the client — it's too late to inject additional <head> tags.
This might seem like an issue, but it actually isn't. See the explanation below.
Bots
If you use vike-react then note that it uses react-streaming which automatically disables HTML Streaming for crawlers (e.g. Googlebot), ensuring crawlers always get all <head> tags. See react-streaming Docs > Bots.
You can use $ curl to see the HTML response that bots and crawlers receive:
# What bots and crawls get: no HTML Streaming, just "classic SSR"$ curl http://localhost:3000/movies# What human users get: HTML Streaming$ curl http://localhost:3000/movies -N -H "User-Agent: chrome"
Consequently, <head> tags intended for bots (SEO, PWA settings, ...) are guaranteed to be included in the HTML. They might be missing for human users, but that isn't an issue.
+title
If <Config title={'some-title'}> runs after the <head> block has already been sent, the HTML snippet <script>document.title = 'some-title'</script> is injected to dynamically update the page title.
Currently, +title is the only setting that uses such mechanism.
Consequently, the <title> tag is guaranteed to be included in the HTML for bots (see section above), while human users see an up-to-date page title.