React Router 7.13.1: URL Masking for Modal PDPs in Hydrogen

The Problem
You want a product quick-view modal that:
- Opens on top of your collection page
- Shows a shareable URL (
/products/sneakers) - Keeps the collection visible in the background
- Works with deep links and browser history
Until now, this required manual backgroundLocation management—a clunky pattern that felt like fighting the framework.

The Solution
React Router 7.13.1 introduces unstable_mask on <Link>. First-class URL masking for Framework/Data Mode.
// routes/collection.tsxexport default function Collection({ loaderData }) {return (<div className="collection-grid">{loaderData.products.map((product) => (<Linkkey={product.id}to={`/collection?product=${product.id}`} // Router stateunstable_mask={`/products/${product.handle}`} // Browser URL><ProductCard product={product} /></Link>))}{/* Modal overlay */}{loaderData.modalProduct && (<dialog open><ProductQuickView product={loaderData.modalProduct} /></dialog>)}</div>)}
How It Works
- Router navigates to
/collection?product=123(internal state) - Browser shows
/products/sneakers(masked URL) - Deep link
/products/sneakersworks normally (mask stripped on SSR) - Back button closes modal, restores collection
Detecting Masked State
import { useLocation } from 'react-router'function ProductModal() {const location = useLocation()// Are we in a modal context?if (location.unstable_mask) {return <ModalProduct />}// Direct navigation - full pagereturn <FullProductPage />}
Hydrogen Use Cases
- Modal PDPs from collection grids
- Image galleries with shareable URLs
- Cart quick-edit from checkout
- Filter previews without navigation
Important Notes
- Marked unstable - API may change before stabilization
- SPA only - Mask removed during SSR (deep links work normally)
- Requires React Router 7.13.1+ in your Hydrogen project
Upgrade
npm install react-router@latest



