# `react-router`
## 7.14.0
### Patch Changes
- UNSTABLE RSC FRAMEWORK MODE BREAKING CHANGE - Existing route module exports remain unchanged from stable v7 non-RSC mode, but new exports are added for RSC mode. If you want to use RSC features, you will need to update your route modules to export the new annotations. ([#14901](https://github.com/remix-run/react-router/pull/14901))
If you are using RSC framework mode currently, you will need to update your route modules to the new conventions. The following route module components have their own mutually exclusive server component counterparts:
| Server Component Export | Client Component |
| ----------------------- | ----------------- |
| `ServerComponent` | `default` |
| `ServerErrorBoundary` | `ErrorBoundary` |
| `ServerLayout` | `Layout` |
| `ServerHydrateFallback` | `HydrateFallback` |
If you were previously exporting a `ServerComponent`, your `ErrorBoundary`, `Layout`, and `HydrateFallback` were also server components. If you want to keep those as server components, you can rename them and prefix them with `Server`. If you were previously importing the implementations of those components from a client module, you can simply inline them.
Example:
Before
```tsx
import { ErrorBoundary as ClientErrorBoundary } from "./client";
export function ServerComponent() {
// ...
}
export function ErrorBoundary() {
return ;
}
export function Layout() {
// ...
}
export function HydrateFallback() {
// ...
}
```
After
```tsx
export function ServerComponent() {
// ...
}
export function ErrorBoundary() {
// previous implementation of ClientErrorBoundary, this is now a client component
}
export function ServerLayout() {
// rename previous Layout export to ServerLayout to make it a server component
}
export function ServerHydrateFallback() {
// rename previous HydrateFallback export to ServerHydrateFallback to make it a server component
}
```
- rsc Link prefetch ([#14902](https://github.com/remix-run/react-router/pull/14902))
- Remove recursion from turbo-stream v2 allowing for encoding / decoding of massive payloads. ([#14838](https://github.com/remix-run/react-router/pull/14838))
- encodeViaTurboStream leaked memory via unremoved AbortSignal listener ([#14900](https://github.com/remix-run/react-router/pull/14900))
## 7.13.2
### Patch Changes
- Fix clientLoader.hydrate when an ancestor route is also hydrating a clientLoader ([#14835](https://github.com/remix-run/react-router/pull/14835))
- Fix type error when passing Framework Mode route components using `Route.ComponentProps` to `createRoutesStub` ([#14892](https://github.com/remix-run/react-router/pull/14892))
- Fix percent encoding in relative path navigation ([#14786](https://github.com/remix-run/react-router/pull/14786))
- Add `future.unstable_passThroughRequests` flag ([#14775](https://github.com/remix-run/react-router/pull/14775))
By default, React Router normalizes the `request.url` passed to your `loader`, `action`, and `middleware` functions by removing React Router's internal implementation details (`.data` suffixes, `index` + `_routes` query params).
Enabling this flag removes that normalization and passes the raw HTTP `request` instance to your handlers. This provides a few benefits:
- Reduces server-side overhead by eliminating multiple `new Request()` calls on the critical path
- Allows you to distinguish document from data requests in your handlers base don the presence of a `.data` suffix (useful for observability purposes)
If you were previously relying on the normalization of `request.url`, you can switch to use the new sibling `unstable_url` parameter which contains a `URL` instance representing the normalized location:
```tsx
// ❌ Before: you could assume there was no `.data` suffix in `request.url`
export async function loader({ request }: Route.LoaderArgs) {
let url = new URL(request.url);
if (url.pathname === "/path") {
// This check will fail with the flag enabled because the `.data` suffix will
// exist on data requests
}
}
// ✅ After: use `unstable_url` for normalized routing logic and `request.url`
// for raw routing logic
export async function loader({ request, unstable_url }: Route.LoaderArgs) {
if (unstable_url.pathname === "/path") {
// This will always have the `.data` suffix stripped
}
// And now you can distinguish between document versus data requests
let isDataRequest = new URL(request.url).pathname.endsWith(".data");
}
```
- Internal refactor to consolidate framework-agnostic/React-specific route type layers - no public API changes ([#14765](https://github.com/remix-run/react-router/pull/14765))
- Sync protocol validation to rsc flows ([#14882](https://github.com/remix-run/react-router/pull/14882))
- Add a new `unstable_url: URL` parameter to route handler methods (`loader`, `action`, `middleware`, etc.) representing the normalized URL the application is navigating to or fetching, with React Router implementation details removed (`.data`suffix, `index`/`_routes` query params) ([#14775](https://github.com/remix-run/react-router/pull/14775))
This is being added alongside the new `future.unstable_passthroughRequests` future flag so that users still have a way to access the normalized URL when that flag is enabled and non-normalized `request`'s are being passed to your handlers. When adopting this flag, you will only need to start leveraging this new parameter if you are relying on the normalization of `request.url` in your application code.
If you don't have the flag enabled, then `unstable_url` will match `request.url`.
## 7.13.1
### Patch Changes
- fix null reference exception in bad codepath leading to invalid route tree comparisons ([#14780](https://github.com/remix-run/react-router/pull/14780))
- fix: clear timeout when turbo-stream encoding completes ([#14810](https://github.com/remix-run/react-router/pull/14810))
- Improve error message when Origin header is invalid ([#14743](https://github.com/remix-run/react-router/pull/14743))
- Fix matchPath optional params matching without a "/" separator. ([#14689](https://github.com/remix-run/react-router/pull/14689))
- matchPath("/users/:id?", "/usersblah") now returns null.
- matchPath("/test\_route/:part?", "/test\_route\_more") now returns null.
- add RSC unstable\_getRequest ([#14758](https://github.com/remix-run/react-router/pull/14758))
- Fix `HydrateFallback` rendering during initial lazy route discovery with matching splat route ([#14740](https://github.com/remix-run/react-router/pull/14740))
- \[UNSTABLE] Add support for `` in Data Mode which allows users to navigate to a URL in the router but "mask" the URL displayed in the browser. This is useful for contextual routing usages such as displaying an image in a model on top of a gallery, but displaying a browser URL directly to the image that can be shared and loaded without the contextual gallery in the background. ([#14716](https://github.com/remix-run/react-router/pull/14716))
```tsx
// routes/gallery.tsx
export function clientLoader({ request }: Route.LoaderArgs) {
let sp = new URL(request.url).searchParams;
return {
images: getImages(),
// When the router location has the image param, load the modal data
modalImage: sp.has("image") ? getImage(sp.get("image")!) : null,
};
}
export default function Gallery({ loaderData }: Route.ComponentProps) {
return (
<>
{loaderData.images.map((image) => (
))}
{/* When the modal data exists, display the modal */}
{data.modalImage ? (
) : null}
>
);
}
```
Notes:
- The masked location, if present, will be available on `useLocation().unstable_mask` so you can detect whether you are currently masked or not.
- Masked URLs only work for SPA use cases, and will be removed from `history.state` during SSR.
- This provides a first-class API to mask URLs in Data Mode to achieve the same behavior you could do in Declarative Mode via [manual `backgroundLocation` management](https://github.com/remix-run/react-router/tree/main/examples/modal).
- RSC: Update failed origin checks to return a 400 status and appropriate UI instead of a generic 500 ([#14755](https://github.com/remix-run/react-router/pull/14755))
- Preserve query parameters and hash on manifest version mismatch reload ([#14813](https://github.com/remix-run/react-router/pull/14813))
## 7.13.0
### Minor Changes
- Add `crossOrigin` prop to `Links` component ([#14687](https://github.com/remix-run/react-router/pull/14687))
### Patch Changes
- Fix double slash normalization for useNavigate colon urls ([#14718](https://github.com/remix-run/react-router/pull/14718))
- Update failed origin checks to return a 400 status instead of a 500 ([#14737](https://github.com/remix-run/react-router/pull/14737))
- Bugfix #14666: Inline criticalCss is missing nonce ([#14691](https://github.com/remix-run/react-router/pull/14691))
- Loosen `allowedActionOrigins` glob check so `**` matches all domains ([#14722](https://github.com/remix-run/react-router/pull/14722))
## 7.12.0
### Minor Changes
- Add additional layer of CSRF protection by rejecting submissions to UI routes from external origins. If you need to permit access to specific external origins, you can specify them in the `react-router.config.ts` config `allowedActionOrigins` field. ([#14708](https://github.com/remix-run/react-router/pull/14708))
### Patch Changes
- Fix `generatePath` when used with suffixed params (i.e., "/books/:id.json") ([#14269](https://github.com/remix-run/react-router/pull/14269))
- Export `UNSAFE_createMemoryHistory` and `UNSAFE_createHashHistory` alongside `UNSAFE_createBrowserHistory` for consistency. These are not intended to be used for new apps but intended to help apps usiong `unstable_HistoryRouter` migrate from v6->v7 so they can adopt the newer APIs. ([#14663](https://github.com/remix-run/react-router/pull/14663))
- Escape HTML in scroll restoration keys ([#14705](https://github.com/remix-run/react-router/pull/14705))
- Validate redirect locations ([#14706](https://github.com/remix-run/react-router/pull/14706))
- \[UNSTABLE] Pass `` value through to the underlying `importmap` `script` tag when using `future.unstable_subResourceIntegrity` ([#14675](https://github.com/remix-run/react-router/pull/14675))
- \[UNSTABLE] Add a new `future.unstable_trailingSlashAwareDataRequests` flag to provide consistent behavior of `request.pathname` inside `middleware`, `loader`, and `action` functions on document and data requests when a trailing slash is present in the browser URL. ([#14644](https://github.com/remix-run/react-router/pull/14644))
Currently, your HTTP and `request` pathnames would be as follows for `/a/b/c` and `/a/b/c/`
| URL `/a/b/c` | **HTTP pathname** | **`request` pathname\`** |
| ------------ | ----------------- | ------------------------ |
| **Document** | `/a/b/c` | `/a/b/c` ✅ |
| **Data** | `/a/b/c.data` | `/a/b/c` ✅ |
| URL `/a/b/c/` | **HTTP pathname** | **`request` pathname\`** |
| ------------- | ----------------- | ------------------------ |
| **Document** | `/a/b/c/` | `/a/b/c/` ✅ |
| **Data** | `/a/b/c.data` | `/a/b/c` ⚠️ |
With this flag enabled, these pathnames will be made consistent though a new `_.data` format for client-side `.data` requests:
| URL `/a/b/c` | **HTTP pathname** | **`request` pathname\`** |
| ------------ | ----------------- | ------------------------ |
| **Document** | `/a/b/c` | `/a/b/c` ✅ |
| **Data** | `/a/b/c.data` | `/a/b/c` ✅ |
| URL `/a/b/c/` | **HTTP pathname** | **`request` pathname\`** |
| ------------- | ------------------ | ------------------------ |
| **Document** | `/a/b/c/` | `/a/b/c/` ✅ |
| **Data** | `/a/b/c/_.data` ⬅️ | `/a/b/c/` ✅ |
This a bug fix but we are putting it behind an opt-in flag because it has the potential to be a "breaking bug fix" if you are relying on the URL format for any other application or caching logic.
Enabling this flag also changes the format of client side `.data` requests from `/_root.data` to `/_.data` when navigating to `/` to align with the new format. This does not impact the `request` pathname which is still `/` in all cases.
- Preserve `clientLoader.hydrate=true` when using `` ([#14674](https://github.com/remix-run/react-router/pull/14674))
## 7.11.0
### Minor Changes
- Stabilize ``/`` ([#14546](https://github.com/remix-run/react-router/pull/14546))
### Patch Changes
- add support for throwing redirect Response's at RSC render time ([#14596](https://github.com/remix-run/react-router/pull/14596))
- Support for throwing `data()` and Response from server component render phase. Response body is not serialized as async work is not allowed as error encoding phase. If you wish to transmit data to the boundary, throw `data()` instead. ([#14632](https://github.com/remix-run/react-router/pull/14632))
- Fix `unstable_useTransitions` prop on `` component to permit omission for backewards compatibility ([#14646](https://github.com/remix-run/react-router/pull/14646))
- `routeRSCServerRequest` replace `fetchServer` with `serverResponse` ([#14597](https://github.com/remix-run/react-router/pull/14597))
- \[UNSTABLE] Add a new `unstable_defaultShouldRevalidate` flag to various APIs to allow opt-ing out of standard revalidation behaviors. ([#14542](https://github.com/remix-run/react-router/pull/14542))
If active routes include a `shouldRevalidate` function, then your value will be passed as `defaultShouldRevalidate` in those function so that the route always has the final revalidation determination.
- `