API reference

useContent()

The useContent() function retrieves the nearest content information for the current route. The returned object includes:

headings: ContentHeading[] | undefined;
menu: ContentMenu | undefined;

The headings array includes data about a markdown file's <h1> to <h6> html heading elements.

Menus are contextual data declared with menu.md files. See menus file definition for more information on the file format and location.

useDocumentHead()

Use the useDocumentHead() function to read the document head metadata.

useDocumentHead() retrieves a readonly DocumentHead object that includes:

export interface DocumentHead {
  /**
   * Represents the `<title>` element of the document.
   */
  readonly title?: string;
  /**
   * Used to manually set meta tags in the head. Additionally, the `data`
   * property could be used to set arbitrary data which the `<head>` component
   * could later use to generate `<meta>` tags.
   */
  readonly meta?: readonly DocumentMeta[];
  /**
   * Used to manually append `<link>` elements to the `<head>`.
   */
  readonly links?: readonly DocumentLink[];
  /**
   * Used to manually append `<style>` elements to the `<head>`.
   */
  readonly styles?: readonly DocumentStyle[];
  /**
   * Arbitrary object containing custom data. When the document head is created from
   * markdown files, the frontmatter attributes that are not recognized as a well-known
   * meta names (such as title, description, author, etc...), are stored in this property.
   */
  readonly frontmatter?: Readonly<Record<string, any>>;
}

All starters include a <RouterHead> component that is responsible for generating the <head> element of the document. It uses the useDocumentHead() function to retrieve the current head metadata and render the appropriate <meta>, <link>, <style> and <title> elements.

src/components/router-head/router-head.tsx
import { component$ } from '@builder.io/qwik';
import { useDocumentHead } from '@builder.io/qwik-city';
 
/**
 * The RouterHead component is placed inside of the document `<head>` element.
 */
export const RouterHead = component$(() => {
  const head = useDocumentHead();
 
  return (
    <>
      <title>{head.title}</title>
 
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
 
      {head.meta.map((m) => (
        <meta {...m} />
      ))}
 
      {head.links.map((l) => (
        <link {...l} />
      ))}
 
      {head.styles.map((s) => (
        <style {...s.props} dangerouslySetInnerHTML={s.style} />
      ))}
    </>
  );
});

useLocation()

Use the useLocation() function to retrieve a RouteLocation object for the current location.

useLocation() allows developers to know the current URL, params as well as if the app is currently navigating, which is useful for showing a loading indicator.

export interface RouteLocation {
  /**
   * Route params extracted from the URL.
   */
  readonly params: Record<string, string>;
  /**
   * The current URL.
   */
  readonly url: URL;
  /**
   * True if the app is currently navigating.
   */
  readonly isNavigating: boolean;
}

The return value of useLocation() is similar to document.location, but it is safe to use on the server where there is no global location object, and it's reactive so it can be tracked.

Path Route Parameters

useLocation() encodes the Route Parameters as params.

Assume you have:

  • File: src/routes/sku/[skuId]/index.tsx
  • User navigates to: https://example.com/sku/1234
  • Then the skuId can be retrieved through useLocation().params.skuId
src/routes/sku/[skuId]/index.tsx
import { component$ } from '@builder.io/qwik';
import { useLocation } from '@builder.io/qwik-city';
 
export default component$(() => {
  const loc = useLocation();
 
  return (
    <>
      <h1>SKU</h1>
      {loc.isNavigating && <p>Loading...</p>}
      <p>pathname: {loc.url.pathname}</p>
      <p>skuId: {loc.params.skuId}</p>
    </>
  );
});

The above code would generate:

<h1>SKU</h1>
<p>pathname: /sku/1234/</p>
<p>skuId: 1234</p>

Notice that useLocation is a read-only API, you should never attempt to mutate the values of the loc object returned. Instead look into the useNavigate() API.

useNavigate()

The useNavigate() function allows to programmatically navigate to the next page without involving a user click or causing a full-page reload. This is the API used by the <Link> component internally to support SPA navigation.

This function returns a nav() function that can be used to "push" to a new path.

Also, useNavigate can be used to SPA refresh the current page, by calling the nav() function without arguments.

import { component$ } from '@builder.io/qwik';
import { useNavigate } from '@builder.io/qwik-city';
 
export default component$(() => {
  const nav = useNavigate();
 
  return (
    <>
      <button
        onClick$={async () => {
          // SPA navigate to /dashboard
          await nav('/dashboard');
        }}
      >
        Go to dashboard
      </button>
 
      <button
        onClick$={async() => {
          // refresh page: call without arguments
          await nav();
        }}
      >
        Refresh page
      </button>
    </>
  );
});

This component will have a button then when clicked, Qwik City will navigate to /dashboard without causing a page to reload.

Notice that for SEO, and accessibility it's better to use the <Link> component instead of useNavigate() programmatically to navigate to a new page after some user interaction.

routeLoader$()

The routeLoader$() function is used to declare a new Server Loader in the given page/middleware or layout. Qwik City will execute all the declared loaders for the given route match. Qwik Components can later reference the loaders, by importing them and calling the returned custom hook function in order to retrieve the data.

import { component$ } from '@builder.io/qwik';
import { routeLoader$ } from '@builder.io/qwik-city';
 
export const useGetTime = routeLoader$(async () => {
  return { time: new Date() }
});
export default component$(() => {
  const signal = useGetTime(); // Signal<{time: Date}>
  console.log('Date': signal.value.time);
  return (
    <div>{signal.value.time.toISOString()}</div>
  )
});

Please refer to the Route Loader section for more information.

routeAction$()

The routeAction$() function is used to declare a new Server Action in the given page/middleware or layout. Qwik City will execute only the invoked action after some user interaction (such as a button click or a form submission).

Please refer to the Server Actions section for more information.

<QwikCityProvider>

The QwikCityProvider component initializes Qwik City in the existing document, providing the necessary context for Qwik City to work, such as useContent() and useLocation().

This component is usually located at the very root of your application, in most of the starters you will find it in the src/root.tsx file:

src/root.tsx
export default component$(() => {
  /**
   * The root of a QwikCity site always start with the <QwikCityProvider> component,
   * immediately followed by the document's <head> and <body>.
   *
   * Don't remove the `<head>` and `<body>` elements.
   */
 
  return (
    <QwikCityProvider>
      <head>
        <meta charSet="utf-8" />
        <link rel="manifest" href="/manifest.json" />
        <RouterHead />
      </head>
      <body lang="en">
        <RouterOutlet />
        <ServiceWorkerRegister />
      </body>
    </QwikCityProvider>
  );
});

QwikCityProvider does not render any DOM element, not even the matched route, it merely initializes Qwik City core logic, because of this reason, it should not be used more than once in the same app.

<QwikCityMockProvider>

The QwikCityMockProvider component initializes a Qwik City context for testing. It provides the necessary context for Qwik City code to work in tests, such as useContent(). Vice versa for useNavigate(), <Link>, useLocation() and so on. It is recommended that you use this in your test files.

QwikCityMockProvider does not render any DOM elements, meaning it won't be visible in snapshots

If you are looking for a general example on how to integrate vitest into your Qwik look checkout the vitest integration documentation

src/components/card.spec.tsx
import { createDOM } from '@builder.io/qwik/testing';
import { QwikCityMockProvider } from '@builder.io/qwik-city';
import { test, expect } from 'vitest';
 
// Component with two props. Uses <Link> internally. Omitted for brevity
import { Card } from './card';
 
const cases = [
  {text: 'qwik', link:'https://qwik.dev/docs/api'}, 
  {text: 'vitest', link: 'https://vitest.dev'}
];
 
test.each(cases)('should render card with %s %s', async ({text, link}) => {
  const { screen, render } = await createDOM();
  await render(
    <QwikCityMockProvider>
      <Card text={text} link={link} />
    </QwikCityMockProvider>,
  );
  expect(screen.innerHTML).toMatchSnapshot();
});

a goto prop can be passed to customize the navigate behavior during tests

src/components/button.spec.tsx
import { $ } from '@builder.io/qwik';
import { createDOM } from '@builder.io/qwik/testing';
import { test, expect, vi } from 'vitest';
 
// Component with one prop. Uses useNavigate internally. Omitted for brevity
import { Button } from '../button';
 
const goto = vi.fn(async (path, options) => {
  console.log(`Navigating to ${path} with ${options}`);
});
 
test('should render the button and navigate', async () => {
  const { screen, render, userEvent } = await createDOM();
  const goto$ = $(goto);
  await render(
    <QwikCityMockProvider goto={goto$}>
      <Button id="button" />
    </QwikCityMockProvider>,
  );
  expect(screen.innerHTML).toMatchSnapshot();
  await userEvent('#button', 'click');
  expect(goto).toHaveBeenCalled();
});

<RouterOutlet>

The RouterOutlet component is responsible for rendering the matched route at a given moment, it uses internally the useContent() to render the current page, as well as all the nested layouts.

This component is usually located as a child of <body>, in most of the starters you will find it in the src/root.tsx file (refer to the example in QwikCityProvider).

<Form>

The Form component is a wrapper around the native <form> element, and it's designed to work side by side with Server Actions.

Since this component uses the native <form> element, it will work with any browser with and without JavaScript enabled, in addition, it enhances the native <form> element by capturing the submit event and preventing the default behavior, so it will behave like an SPA (Single Page Application) instead of a full page reload.

src/routes/login/index.tsx
import { component$ } from '@builder.io/qwik';
import { Form, routeAction$ } from '@builder.io/qwik-city';
 
// this action will be called when the form is submitted
export const useLoginAction = routeAction$((data, { cookies, redirect }) => {
  if (validate(data.username, data.password)) {
    cookies.set('auth', getAuthToken(data.username));
    throw redirect(302, '/dashboard');
  }
});
 
export default component$(() => {
  const login = useLoginAction();
 
  return (
    <Form action={login}>
      <input type="text" name="username" />
      <input type="password" name="password" />
      <button type="submit">Login</button>
    </Form>
  );
});

The Link component works like the <a> anchor element, but instead of causing a full page to reload, it will navigate as a SPA (Single Page Navigation). This is useful if you need to navigate without losing your current state.

Notice that full-page reloads in Qwik are extremely cheap, other frameworks abuse SPA links because a full-page reload requires JS to hydrate and re-execute everything. This is not the case for Qwik. We found in our internal testing that using <a> usually leads to the most snappy interactions.

Under the hood, the <Link> component uses the useNavigate() API and prevents the default behavior of the native <a>:

import { component$ } from '@builder.io/qwik';
import { useNavigate } from '@builder.io/qwik-city';
 
export const Link = component$<LinkProps>((props) => {
  const nav = useNavigate();
 
  return (
    <a
      preventdefault:click
      onClick$={() => {
        nav(props.href);
      }}
      {...props}
    >
      <Slot />
    </a>
  );
});

Usage

import { component$ } from '@builder.io/qwik';
import { Link } from '@builder.io/qwik-city';
 
export default component$(() => {
  return (
    <div>
      <a href="/docs" class="my-link">
        full-page reload
      </a>
      <Link href="/docs" class="my-link">
        spa navigation
      </Link>
    </div>
  );
});

Contributors

Thanks to all the contributors who have helped make this documentation better!

  • manucorporat
  • adamdbradley
  • the-r3aper7
  • nnelgxorz
  • cunzaizhuyi
  • jakovljevic-mladen
  • barbosajlm
  • Eucer
  • eltociear
  • literalpie
  • Mhmdrza
  • ulic75
  • mhevery
  • jordanw66
  • igorbabko
  • mrhoodz
  • VinuB-Dev
  • billykwok
  • julianobrasil
  • hamatoyogi