useMediaQuery SSR fallback behavior remains undecided in MUI
0 reputation · 08 Jan 2020, 21:59 UTC
0 reputation · 08 Jan 2020, 21:59 UTC
The useMediaQuery hook reads breakpoints from the theme and relies on window.matchMedia, which is absent during server‑side rendering. Without a custom ssrMatchMedia function supplied via the theme, the hook defaults to false, often causing hydration mismatches in frameworks like Next.js. The MUI team has discussed adding a built‑in ssrMatchMedia implementation to the default theme but has not reached consensus, leaving the fallback strategy as an open design decision.
Developers must currently choose between providing a project‑specific ssrMatchMedia, guarding the hook with typeof window !== 'undefined', or accepting the initial false render and a client‑side update. Each approach carries trade‑offs for bundle size, layout shift, and API surface.
What is the current status of the proposed default ssrMatchMedia implementation? Are there any documented workarounds that avoid both hydration warnings and a flash of incorrect layout? Does the MUI roadmap indicate a timeline for resolving this behavior?
35275 reputation · 09 Jan 2020, 02:30 UTC
As of the latest MUI releases (v5 and v6), there is no built‑in default ssrMatchMedia implementation in the theme. The hook still falls back to false on the server unless you supply your own ssrMatchMedia function via the theme or use an escape hatch like noSsr. The MUI team has not reached consensus on adding a server‑side guess, so the behavior remains an open design decision with no published timeline for resolution.
useMediaQuery reads breakpoints from the theme and calls window.matchMedia, which is undefined during SSR.ssrMatchMedia, the hook returns false on the server, leading to hydration mismatches in frameworks such as Next.js.ssrMatchMedia as a theme option (e.g., createTheme({ ssrMatchMedia: fn })) precisely for projects to inject a stub.noSsr prop (where available) skips rendering until the client, which is an officially acknowledged workaround.useEffect‑set state) can also suppress hydration warnings by rendering a placeholder until the client evaluates the query.The team has discussed a default implementation that would guess the client viewport from request headers (User‑Agent or Sec‑CH‑UA‑Viewport‑Width). Because such guesses can be wrong for tablets, desktop mode toggles, or split‑screen layouts, they have not merged a solution. Until a reliable heuristic is agreed upon, the fallback stays as user‑land responsibility.
npm list @mui/material) to confirm the exact API shape.ssrMatchMedia function in the theme that derives a width from available hints:
import { createTheme } from '@mui/material';
const getWidthFromUA = (ua) => {
// simple heuristic – replace with a library or client‑hint parsing if needed
const match = ua.match(/Width=(\d+)/);
return match ? parseInt(match[1], 10) : 1200; // assume desktop width
};
const theme = createTheme({
ssrMatchMedia: (query) => {
const width = typeof window !== 'undefined' ? window.innerWidth : getWidthFromUA(typeof navigator !== 'undefined' ? navigator.userAgent : '');
// parse min/max‑width from query (simplified)
const max = query.match(/max-width:\s*(\d+)/);
const min = query.match(/min-width:\s*(\d+)/);
let matches = true;
if (max) matches = width <= parseInt(max[1], 10);
if (min) matches = width >= parseInt(min[1], 10);
return { matches };
},
});
useMediaQuery with the themed provider:
<ThemeProvider theme={theme}>
<MyBreakpointDependentComponent />
</ThemeProvider>
noSsr prop (if your MUI version supports it) to render nothing on the server and update on the client. This eliminates hydration warnings but may cause a layout shift if the element is above the fold.div) and switch to the real UI after mount using a useEffect‑set flag. This also avoids warnings but incurs a brief flash of the placeholder.To confirm whether the noSsr prop is available in your setup, please specify the exact MUI version you are using (e.g., @mui/material@5.15.0 or @mui/joy@6.0.0).
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.