DEV Community

Cover image for Contextual routing and modal routes in Next.js
Andrea Carraro
Andrea Carraro

Posted on • Updated on

Contextual routing and modal routes in Next.js

Contextual routing is a widespread UI technic made popular by applications like Facebook, Instagram and Reddit usually in the shape of Modal Routes.

Modal routes pattern consists of opening a modal while temporary replacing the current URL (usually with the one pointing to the resource being displayed in-modal):

Basic contextual routing

Next.js router recently added support for contextual routing by simply providing Link component with the relevant href + as props.

import Link from 'next/link';

<Link
  href="/post-list?postId=42"
  as="/post/42"
>
  <a>Open modal route</a>
</Link>
Enter fullscreen mode Exit fullscreen mode

The above example would update browser address' path to /post/42 while rendering the page specified as href (/post-list with postId parameters equal to 42).

This leads to 2 possible outcomes:

  • user closes the modal and the URL is restored to the value where contextual routing was started (in our case /post-list)
  • user refreshes the page landing on the actual page described by the URL

HREF property

The minimal necessary information to render a Next.js page consists of:

  • page pathname (eg. /post/[id])
  • page params (eg. id=42)

The main idea behind contextual routing consists of creating a divergence between the URL displayed and the page actually rendered.

Since contextual navigation replaces the URL, it means that rendered pages cannot rely anymore on the URL to retrieve pathname and relative page params.

href prop plays therefore the crucial role of supplying the aforementioned information as a single string:

// page pathname + all required params as query string
const href = router.pathname + `?param1=1&param2=2`
Enter fullscreen mode Exit fullscreen mode

Real world scenario

Before starting contextual routing navigation you need to know 3 information beforehand:

  • as path (the path displayed during contextual routing)
  • href path
  • return href (the path to return to to end contextual routing)

href and return href are trivial to get when the starting page has a static path, let's say: /post-list.

Things gets trickier when starting page path is not statically defined, in other words when the path includes dynamic parameters like: /post-list/bob (where bob is an author name).

This means href has to be generated from initial page pathname plus route params and then persisted during the whole contextual routing navigation in order to keep the page alive.

On top of this a developer might want to extend available route params with extra ones to be made available during contextual navigation. Eg:

const as = 'post/42'
const returnHref = 'post-list/bob'
const href = 'post-list/[author]?author=bob&id=42'
Enter fullscreen mode Exit fullscreen mode

The example above provides id=42 as extra param to make the modal route aware of which post should be displayed.

This demo shows a basic implementation of what you just read.

The devil is in the details

There's is an extra pitfall worth mentioning: the application would loose reference to returnHref after a page reload followed by one or more back button presses.

This means the application won't be able to restore the initial URL while the modal route is open, breaking the user flow or forcing Next.js to reload the page.

One hook to rule them all

In order to overcome this issue and make contextual routing setup trivial, I wrapped the necessary boilerplate logic in a React hook published as next-use-contextual-routing.

You can read the source code and star it on github. It's fully tested and weights ~0.5 kb gzipped.

import Link from 'next/link';
import { useContextualRouting } from 'next-use-contextual-routing';

//...
const { makeContextualHref, returnHref } = useContextualRouting();

<Link
  as="/post/42"
  href={makeContextualHref({ id: 42 })}
  shallow
>
  <a>Open modal route</a>
</Link>

Enter fullscreen mode Exit fullscreen mode

The hook returns 2 values:

makeContextualHref: a function returning the href value necessary to start contextual navigation. It optionally accepts an object providing extra href parameters.

returnHref: the path to return to to close contextual navigation.

The demo mentioned above makes use of next-use-contextual-routing hook. Check it out to make sure it can suit your needs.

Top comments (6)

Collapse
 
vvo profile image
Vincent Voyer

Hey there, I featured this article in the latest Next.js News: twitter.com/vvoyer/status/13182876... (at the bottom of the newsletter content).

BTW, are you sure it's ~500 kb gzipped? Seems like a lot :)

Collapse
 
toomuchdesign profile image
Andrea Carraro

Hi Vincent, it's definitely a lot! I've just refactored the article's dev dependencies and the weight got down to 0.5kb :) Thank you

Collapse
 
dorjitshering profile image
Dorji Tshering

Hi Andrea, I am coming here again after getting a peer dependency error of the package during my deployment. The last published package is configured to use next version <= 12. I saw the repo and the version was updated to 13 there. Looks like the package needs to republished with latest changes? I am still waiting for the latest version that supports next 13. I really hope you see this. Been trying to reach you via twitter and contact from your website. Thanks.

Collapse
 
dorjitshering profile image
Dorji Tshering

Thank you so so much for this article and that precious hook. I was able to get the things done for home route i.e. '/', but couldn't get it work for dynamic routes and spent hours googling until I reached here. Tried the hook and now it is working perfectly. Thanks once again and please keep the hook alive as long as you can!!

Collapse
 
michaelsoriano profile image
Michael Soriano

This is almost what I needed. But I what really want is - when you do a hard reload, the page looks exactly the same - with the modal open etc.

Collapse
 
100000multiplier profile image
multiply.today

Wow awesome work, thank you!