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.)

By default, vite-plugin-ssr does Server Routing, which means that 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.

For smoother navigations, we can use Client Routing.

// 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 Wildcard (e.g. /product/:params*) and then use a routing library (Vue Router, React Router, ...) for that page, but we recommend the aforementioned solution instead as it is simpler.

Edit this page