Nested Routes

A nested route (aka sub route) is, essentially, when we have a route with multiple parameters, for example /product/:productId/:productView.

URL                        productId     productView
/product/1337              1337          null
/product/1337/pricing      1337          pricing
/product/42/reviews        42            reviews

We can define a Route String or Route Function that has multiple parameters.

// product.page.route.js

export default `/product/:productId/:productView`
// product.page.route.js

// We can also use a Route Function
export default (pageContext) => {
  const { url } = pageContext
  if (!url.startsWith('/product/')) return false
  const [productId, productView] = url.split('/').slice(2)
  return { routeParams: { productId, productView } }
}

Usually, the sub route is used for navigating some (deeply) nested view:

/product/42/pricing                   /product/42/reviews
+------------------+                  +-----------------+
| Product          |                  | Product         |
| +--------------+ |                  | +-------------+ |
| | Pricing      | |  +------------>  | | Reviews     | |
| |              | |                  | |             | |
| +--------------+ |                  | +-------------+ |
+------------------+                  +-----------------+

If our sub routes don't need URLs (the Product Pricing page and the Product Reviews page share the same URL /product/42), then we can simply use a stateful component instead. (When the user clicks on a "pricing" link, the stateful component changes an internal state productView to 'pricing' to switch to the pricing view.)

Client Rendering

For smooth nested routes, we recommend using Client Routing.

If we use Server Routing, when the user navigates from /product/42/pricing to /product/42/reviews, the old page /product/42/pricing is fully replaced with the new page /product/42/reviews leading to a jittery experience.

// product.page.client.js

import { useClientRouter } from 'vite-plugin-ssr/client/router'

// We use Client Routing so that, when the user navigates from `/product/42/pricing`
// to `/product/42/reviews`, only the relevant (deeply) nested view is updated (instead of
// a full HTML reload).

// Note that we override `_default.page.client.js`. This means all our other pages can use
// Server Routing while this page uses Client Routing.
// (If we already use `useClientRouter()` in `_default.page.client.js`, then we don't need to
// create this `product.page.client.js` file.)

useClientRouter({
  render(pageContext) {
    /* ... */
  }
})

We can then use <a href="/product/42/reviews" keep-scroll-position /> / navigate('/product/42/reviews', { keepScrollPosition: true }) to avoid the browser to scroll to the top upon navigation.

Alternatively, we can use a Route String catch-all parameter (e.g. /product/*) and then use a routing library (Vue Router, React Router, ...) for that page, but we recommend the aforementioned solution instead as it is simpler.