Skip to content

Centered dialog

Content-sized, centered, zoom+fade. The example's own class sets the width; drag does nothing here.

<Sheet.Root side="center">
<Sheet.Trigger>Delete project</Sheet.Trigger>
<Sheet.Content className="sheet" style={{ width: 400 }}>
<Sheet.Title>Delete this project?</Sheet.Title>
<Sheet.Description>This can't be undone.</Sheet.Description>
<Sheet.Close>Cancel</Sheet.Close>
</Sheet.Content>
</Sheet.Root>

side="center" is a first-class presentation, not a CSS trick bolted onto a bottom sheet. The panel is content-sized and placed in the middle of the viewport instead of anchored to an edge: no travel range, no detents, no drag. It opens and closes with a zoom+fade (scale from 0.95 to 1, with opacity) on the same spring every other sheet uses, instead of the slide a bottom or side sheet plays.

Core sets no width on the panel, only guard rails: max-inline-size defaults to min(560px, 100%) so a dialog with no styling at all never touches the viewport edges. Size it the same way you’d size any card:

.sheet {
width: 400px;
}

Wider dialog? Raise the guard rail instead of fighting it:

.sheet {
--scrollsheet-center-max-inline: 720px;
}

--scrollsheet-center-gutter (default 20px) is the minimum breathing room against the viewport edge on small screens, independent of the width you choose.

A centered dialog with a text input shifts up above the on-screen keyboard automatically. It reads the same --scrollsheet-keyboard inset the bottom sheet engine already writes, so there’s no separate keyboard mode to opt into.

Escape and a backdrop click both dismiss, same as every other side. dismissible, escapeDismissible, and backdropDismissible all work unchanged.

The ~4% of browsers without <dialog> support already render every sheet as a plain centered modal (see Browser support). A center dialog’s fallback is nearly indistinguishable from its normal path, so there’s nothing extra to account for.

Reach for center when the content is a short, self-contained decision that reads naturally as a dialog: a confirmation, a one-field form, an alert. Keep the default bottom (or side) presentation for anything a thumb should be able to drag: multi-step flows, longer scrollable content, or a sheet meant to feel native on a phone. side="center" is a fixed choice, not a breakpoint. For a sheet that should dock as a centered dialog on desktop but stay a full-bleed bottom sheet on mobile, see Responsive profiles instead: desktopSide="center" gets you exactly that as two props.