Skip to content

Responsive profiles

Under 720px it drags like a sheet; at 720px and wider the same component opens as a centered dialog. Resize to cross the line.

<Sheet.Root side="bottom" desktopSide="center">

That’s the whole pattern: a bottom sheet on a phone, a centered dialog once the viewport is wide enough to call it one. No matchMedia hook, no conditional detents, no branching on which markup to render. side and desktopSide are both first-class presentations already; this just picks between them for you.

desktopSide takes over at desktopBreakpoint, 768 by default: the same line the desktop presentation CSS switches on, so a sheet using either mechanism changes shape at the same viewport width. Override it per Sheet.Root:

<Sheet.Root side="bottom" desktopSide="center" desktopBreakpoint={1024}>

desktopBreakpoint only means something paired with desktopSide. Set alone it warns once in dev and does nothing, because there’s nothing for the crossing to switch between.

Resize past the breakpoint with the sheet already open and it re-presents instantly: no morph, no dismiss-and-reopen, just a new presentation on the same open sheet. Resize back down and it flips back the same way, in either direction, as many times as the viewport crosses the line.

Server render and the first client paint both resolve to the base side. The matchMedia subscription that can promote it to desktopSide only lands after mount, never during render, so hydration never disagrees with the server about which side it is. In practice this is invisible: a Sheet.Root renders nothing until it’s opened, and by the time a user can open one, mount has already happened and the subscription has already resolved. There’s no flash of the wrong presentation to design around.

side and desktopSide take the same five values ('bottom' | 'top' | 'left' | 'right' | 'center') and don’t have to relate to each other. A bottom sheet that becomes a left drawer on desktop:

<Sheet.Root side="bottom" desktopSide="left">

A right panel on mobile that centers itself on desktop, a top sheet that becomes a right drawer, whatever the layout calls for. desktopSide is just the presentation side swaps to, not a fixed mobile-to-desktop story.

Desktop presentation is CSS: past 768px, core restyles the same side into a docked drawer or a squared-off edge, no prop involved. desktopSide replaces the presentation outright, swapping which side is even in effect. Reach for the CSS default when a wider viewport should just make the current side look native to a pointer and keyboard. Reach for desktopSide when desktop should read as a different kind of surface entirely, most often a bottom sheet becoming a centered dialog.