# Client-side routing for dynamic pages commercetools Frontend uses the Next.js router for client-side routing, making it simple to create links to any dynamic page as long as the `dynamic-page-handler` has the logic to handle the created links. In this article, we'll see how to create a dynamic page and link it to other pages on the frontend. Let's modify our Star Wars example by adding 2 new pages: - A static page `/star-wars/films` showing a list of all the Star Wars films - A dynamic page `/star-wars/film/[filmId]` showing the details of the Star Wars film with `filmId` ## Create the film details page 1. Add the logic to grab the `filmId` from the URL pattern `/star-wars/film/[filmId]` so it can be used to fetch the film information from SWAPI, to the `dynamic-page-handler` present in the `backend/index.ts` file ```typescript title="Dynamic page handler implementation for the film details page" 'dynamic-page-handler': async (request: Request): Promise => { const [_, filmId] = request.query.path.match(new RegExp('/star-wars/film/([^ /]+)')); if (filmId) { return await axios .post('https://swapi-graphql.netlify.app/.netlify/functions/index', { query: '{film(id:"' + filmId + '") {id, title, openingCrawl, releaseDate}}', }) .then((response): DynamicPageSuccessResult => { return { dynamicPageType: 'example/star-wars-film-page', dataSourcePayload: response.data, pageMatchingPayload: response.data, }; }) .catch((err) => { return { dynamicPageType: 'example/star-wars-film-page', dataSourcePayload: { err }, pageMatchingPayload: { err }, }; }); } return null; }, ``` 2. Create a custom Frontend component in the Studio with the following schema ```json title="Schema for the example/star-wars-film Frontend component" { "tasticType": "example/star-wars-film", "name": "Star wars movie", "icon": "list", "category": "Documentation Examples", "schema": [ { "name": "Configuration", "fields": [ { "label": "film", "field": "film", "type": "dataSource", "dataSourceType": "example/star-wars-film", "required": true } ] } ] } ``` To do that, go to the **Components** area in the Studio, click **Create schema**, paste the above JSON into the editor, then click **Publish** 3. Create a React component in the `tastics/star-wars/film/index.tsx` that displays the film data passed to the page by the `dynamic-page-handler` ```typescript title="React component to render film details" import React from 'react'; const StarWarsFilmDetails = ({ data }) => { const film = data.data.film || {}; return (

{film.title}

{film.openingCrawl}

Released on {film.releaseDate}

); }; export default StarWarsFilmDetails; ``` 4. Register `StarWarsFilm` component in the `tastics/index.tsx` file ```typescript title="Register the example/star-wars-film Frontend component" import NotFound from './not-found'; import Markdown from './markdown/tastic'; import StarWarsFilm from './star-wars/movie'; export const tastics = { default: NotFound, 'example/star-wars-film': StarWarsFilm, 'training/content/markdown': Markdown, }; ``` 5. From the Studio homepage, or the from the left menu, go to **Developer > Dynamic pages**. 6. Click **Create schema**, then paste the following JSON into the editor, and click **Publish**. ```json title="Dynamic page schema for film details page" { "dynamicPageType": "example/star-wars-film-page", "name": "Star wars film", "category": "Documentation Example", "icon": "stars", "dataSourceType": "example/star-wars-film", "isMultiple": true } ``` You need to use the **Production** environment while creating the dynamic page. 7. Go to the **Dynamic pages** section, select **Star wars film**, and create a **New page version** (testbed) in the Default page rule ![Site builder with Default page rule and testbed page version selected in the Live section.](https://docs.commercetools.com/frontend-development/images/migrated/4d5eaae-0193c70-dynamic-page-version2x.png) 8. Use the **Star Wars film** component on the testbed page version as shown below ![Page builder with Star wars film component in the main section and Star wars film data source selected.](https://docs.commercetools.com/frontend-development/images/migrated/80bc792-9decc2e-add-component-dynamic-page.png) 9. Open `, the film detail page renders in the browser. ![Film details page rendered in the browser.](https://docs.commercetools.com/frontend-development/images/migrated/e83f752-film-details-page.png) Now that the `/star-wars/film/filmId` page is working, let's create the `star-wars/films` page to list links to all films. ## Create the films list page You need a data source extension to fetch the list of movies from the SWAPI and a custom Frontend component to render the list of movies for the films page. 1. From the Studio homepage or the left menu, go to **Developer > Data sources**. 2. Create the schema for the data source. ```json title="Data source schema for the example/star-wars-all-films data source" { "customDataSourceType": "example/star-wars-all-films", "name": "Star wars all films", "category": "Content", "icon": "source", "schema": [] } ``` 3. Implement the data source extension in the `backend/index.ts` file ```typescript title="Data source extension implementation for example/star-wars-all-films" 'example/star-wars-all-films': async ( config: DataSourceConfiguration, context: DataSourceContext, ): Promise => { return await axios .post('https://swapi-graphql.netlify.app/.netlify/functions/index', { query: '{allFilms { films {id, title, episodeID}} }', }) .then((response) => ({ dataSourcePayload: response.data, })) } ``` 4. Go to the **Components** area and create a schema that specifies the data source you created earlier in the `schema` field ```json title="Schema for example/star-wars-all-films" { "tasticType": "example/star-wars-all-films", "name": "Star wars films", "icon": "list", "category": "Documentation Examples", "schema": [ { "name": "Configuration", "fields": [ { "label": "films", "field": "films", "type": "dataSource", "dataSourceType": "example/star-wars-all-films", "required": true } ] } ] } ``` 5. Implement the React component in the `index.ts`, which renders links from the array of films provided by the data source extension ```typescript title="React component to render list of films" import React from 'react'; import Link from 'next/link'; const StarWarsFilms = ({ data }) => { return (

Star wars films

{data.films.dataSource.data.allFilms.films.map((film) => ( {film.title} ))}
); }; export default StarWarsFilms; ``` 6. Register this component in the `tastics/index.tsx` file ```typescript title="Register the example/star-wars-all-films Frontend component" import NotFound from './not-found'; import Markdown from './markdown/tastic'; import StarWarsFilms from './star-wars/all-films'; import StarWarsFilm from './star-wars/film'; export const tastics = { default: NotFound, 'example/star-wars-all-films': StarWarsFilms, 'example/star-wars-film': StarWarsFilm, 'training/content/markdown': Markdown, }; ``` 7. Go to the\*\* Site builder\*\*, click **New**, then **Create page folder**, input a name (we're calling ours `Star wars`) 8. Select your new page folder, then click **New**, select **Create page version**, input a name (we're using `films`) and click **Save** 9. Drag your component into the layout element, select the `Star wars all films` data source, and click **Save** ![Page builder with Star wars films film component in the main section and Star wars all films data source selected](https://docs.commercetools.com/frontend-development/images/migrated/5cc8356-4bb658e-add-component-static-page2x.png) 10. Open `, the films list renders in the browser. ![Films list rendered in the browser](https://docs.commercetools.com/frontend-development/images/migrated/16ec160-films-list-page.png) ## Related pages - [Area overview page with navigation](/frontend-development.md) - [Previous page: Sitemaps](/frontend-development/sitemaps.md) - [Next page: Creating a redirect component](/frontend-development/client-side-redirect-component.md) - [Search documentation and API specs](/search.md)