<head> customization

HTML places the <head> tag as the first element within <html> (at the very top of the HTML content). The <head> section is not something that your route component renders directly, yet you still need to control its content. This can be achieved by exporting a head property (or function) from your page component.

Static Document Head

If all we need to do is set the title of the page, we can do it in the head (and optional meta, links and styles) export of the component like so:

// File: src/routes/product/[skuId]/index.tsx
import { component$ } from '@builder.io/qwik';
import type { DocumentHead } from '@builder.io/qwik-city';

export default component$(() => {...});

export const head: DocumentHead = {
  title: 'Product Details',
  meta: [...],
  links: [...],
  styles: [...],
};
// File: src/root.tsx
export default component$(() => {
  const head = useDocumentHead();

  return (
    <QwikCityProvider>
      <head>
        <meta charSet="utf-8" />
        <title>{head.title}</title>
        {head.meta.map((m) => (
          <meta {...m} />
        ))}
        {head.links.map((l) => (
          <link {...l} />
        ))}
        {head.styles.map((s) => (
          <style {...s.props} dangerouslySetInnerHTML={s.style} />
        ))}
      </head>
      <body>
        <RouterOutlet />
      </body>
    </QwikCityProvider>
  );
});

Dynamic Document Head

The above case works for simple situations where we just want to set the document's title of the page with a static value. In a case where we need to set the title dynamically, for example, to include the product title, we can use a function:

// File: src/routes/product/[skuId]/index.tsx
import { component$ } from '@builder.io/qwik';
import type { DocumentHead } from '@builder.io/qwik-city';

type EndpointData = ProductData | null;

interface ProductData {
  skuId: string;
  price: number;
  description: string;
}

export const onGet: RequestHandler<EndpointData> = async ({ params }) => { ... };

export default component$(() => {...});

export const head: DocumentHead<EndpointData> = ({ data }) => {
  return {
    title: `Product - ` + data.description
  };
};

The second case is a bit more complicated but it showcases how we can set the title of the page with the value that is retrieved from the onGet endpoint. (See data documentation for retrieving data.) The Qwik City invokes onGet to retrieve the data for the route and then passes the data to the head function allowing it to create a custom title.

Resolved Document Head

An advanced case is that a layout may want to modify the document title of an already resolved document head. In the example below, the page component returns the title of Foo. Next, the containing layout component can read the value of the page's document head and modify it. In this example, the layout component is adding Bar to the title, so that when rendered, the title will be Foo Bar. Every layout in the stack has the opportunity to return a new value.

──src/
  └─routes/
    ├─index.tsx
    └─layout.tsx
// File: src/routes/index.tsx
export const head: DocumentHead = {
  title: `Foo`,
};
// File: src/routes/layout.tsx
export const head: DocumentHead<EndpointData> = ({ head }) => {
  return {
    title: `${head.title} Bar`,
  };
};
Made with ❤️ by