Pages
Both pages and endpoints in Qwik City are created by adding a new index.tsx
file in the src/routes
directory.
The only difference is that a page exports a default
Qwik component, which will be rendered as the content of the page, while an endpoint only exports a onRequest
, onGet
, onPost
, onPut
, onDelete
, onPatch
, onHead
function, which will be used to handle the incoming request.
Components
Page content can be created using Qwik components. The component representing the content should be exported as a default
export.
Let's assume you have your routes set up like this:
src/
βββ routes/
βββ some/
βββ path/
βββ index.tsx # https://example.com/some/path
// File: src/routes/some/path/index.tsx
import { component$ } from '@builder.io/qwik';
// Notice the default export
export default component$(() => {
return <h1>Hello World!</h1>;
});
Importing other components
You can build complex views by composing multiple components within each other. To do that import other components into your index.tsx
file.
src/
βββ components/
β βββ heading.tsx
βββ routes/
βββ some/
βββ path/
βββ index.tsx # https://example.com/some/path
βββ sub_component.tsx
Inside index.tsx
you can create a component that is exported as default
export. Content is created by writing a template with JSX-Syntax. Every component-function returns the template that should be rendered on the screen. If you want to learn more about the component anatomy, please see components documentation.
The following component will be rendered at https://example.com/some/path
according to the directory-structure, we have set up above.
// File: src/routes/some/path/index.tsx
import { component$ } from '@builder.io/qwik';
import Heading from '../../../components/heading';
import SubComponent from './sub_component';
export default component$(() => {
return (
<>
<Heading />
<h2>Hello World!</h2>
<SubComponent />
</>
);
});
// File: src/components/heading.tsx
import { component$ } from '@builder.io/qwik';
export default component$(() => {
return <h1>Site Heading</h1>;
});
// File: src/routes/some/path/sub_component.tsx
import { component$ } from '@builder.io/qwik';
export default component$(() => {
return <div>Other component content.</div>;
});
head
export
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.
// src/routes/index.tsx
import { component$ } from '@builder.io/qwik';
export default component$(() => {
return <h1>Hello World</h1>;
});
export const head = {
title: 'My Page',
meta: [
{
name: 'description',
content: 'My page description',
},
],
};
Every endpoint (index) and layout can export a
head
property (or function) that returns aDocumentHead
object. TheDocumentHead
object is used to resolve the title of the page, as well as the meta, links and styles.
Dynamic head
In the example above, the head
is static. However, you can also export a function that returns a DocumentHead
object. This allows you to dynamically set the title of the page based on the data that is retrieved from loaders
or request handlers that executed before the page component is rendered.
// src/routes/product/[productId]/index.tsx
import { component$ } from '@builder.io/qwik';
import type { DocumentHead } from '@builder.io/qwik-city';
export const useGetProductData = loader$(({ params }) => {
const product = db.getProduct({ id: params.productId });
return product;
});
export default component$(() => {
const product = useGetProductData();
return (
<div>
<h1>{product.value.title}</h1>
<h1>{product.value.description}</h1>
</div>
);
});
export const head: DocumentHead = ({ params, resolveValue }) => {
const product = resolveValue(useGetProductData);
return {
title: `Product "${product.title}"`,
meta: [
{
name: 'description',
content: product.description,
},
{
name: 'id',
content: params.productId,
},
],
};
};
Nested layouts and 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 MyCompany -
to the title, so that when rendered, the title will be MyCompany - Foo
. 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: `MyCompany - ${head.title}`,
};
};