How toDowngrade to MPA if Users Prefer Reduced Data in React Router

Users can enable a setting in their devices to indicate to websites that they prefer reduced data usage.

When this setting is enabled, websites should reduce the data they use. We can achieve this by disabling images, videos, and other media. It can also be done by disabling JavaScript.

In React Router, we can quickly stop sending client-side JS, and if we use progressive enhancement techniques, the user experience will be the same.

Detect Save Data in the loader

Browsers let you know if the user has enabled Data Saver by setting the Save-Data header to on in the request. You can detect this in your server-side code and send a different response.

app/routes/root.tsx
import type { Route } from "./+types/root"; import { data } from "react-router"; export async function loader({ request }: Route.LoaderArgs) { let saveData = request.headers.get("Save-Data") === "on"; return data({ saveData }); }

Disable JS

We can do this by not rendering the Scripts component in the root route.

app/routes/root.tsx
import type { Route } from "./+types/root"; import { data } from "react-router"; import { Links, Meta, Outlet, Scripts, ScrollRestoration, useLoaderData, } from "react-router"; export async function loader({ request }: Route.LoaderArgs) { let saveData = request.headers.get("Save-Data") === "on"; return data({ saveData }); } export default function App() { let { saveData } = useLoaderData<typeof loader>(); return ( <html lang="en"> <head> <meta charSet="utf-8" /> <meta name="viewport" content="width=device-width,initial-scale=1" /> <Meta /> <Links /> </head> <body> <Outlet /> {!saveData ? ( <> <ScrollRestoration /> <Scripts /> </> ) : null} </body> </html> ); }

By conditionally rendering Scripts and ScrollRestoration we could downgrade the UX from a SPA that may need hundreds of KB of JS to an MPA with 0 KB of JS that still works thanks to progressive enhancement.

Finally, remember to add Vary: Save-Data to your response headers so that the browser knows to cache the response separately for users with and without Data Saver enabled in case you're using Cache-Control.