Skip to content
Component installs need the registry setup
VegaStack Design

Elevation

Bordered surfaces by default, and Tailwind's own shadow steps where a surface floats.

Last updated

Surfaces are separated by borders; shadow means a surface genuinely floats above the page. There is no single named overlay role any more — a floating surface reaches for Tailwind's own shadow-sm, shadow-md or shadow-lg, at the weight upstream gives that component.

Floating surface

active tab chip · floating sidebar · inset main

shadow-sm

Floating surface

popover · menu · select

shadow-md

Floating surface

sheet · submenu

shadow-lg

Where shadow appears

  • shadow-md — popovers, menus and selects.
  • shadow-lg — sheets and submenus.
  • shadow-sm — the active tab chip, the floating sidebar, the inset main area.
  • none — cards, panels, rows, inputs and resting controls, which separate with border-border (floating surfaces draw the same border under their shadow — see below).

Sticky surfaces gain a separating border when they detach from adjacent content; they do not acquire an invented elevation tier.

Overlay widths

Dialog, Sheet (left and right) and CommandDialog share one width scale, set with size (OVL-16). Below sm every one of them fills the viewport less a 1rem gutter (a side sheet fills it); the scale applies from sm up. AlertDialog keeps its own narrower pair.

sizeWidth from smUse
smmax-w-xsA single question or one field
defaultmax-w-smA short form or a confirmation with context
lgmax-w-2xlA form of up to about ten fields, or a two-column form
xlmax-w-5xlA review, a comparison, or a table the user works inside

A long form in a Dialog or Sheet goes in its body part (DialogBody, SheetBody), which scrolls while the header and footer stay put.

Borders, not rings

Every card and every floating surface — dialog, alert dialog, popover, hover card, select, combobox, the three menus and the navigation-menu panel — draws a real 1px border border-border. None of them carries a ring-* outline. Shadow is the only thing that changes between a resting card and a floating popover; the edge is the same hairline on both.

Upstream shadcn draws that edge as ring-1 ring-foreground/10, a box-shadow. The system took it at the reset and reversed it (decision BRD-1, 23-09-2026), for three reasons:

  • It read as a stray outline. A foreground-tinted ring sits outside the box and looks like a focus or selection state that nobody asked for, not like the surface's own edge.
  • It vanishes in forced colours. Windows High Contrast drops box-shadows, so a ring-edged surface lost its boundary entirely; a border is repainted in the system colour.
  • It contradicted the rest of the system. Inputs, tables, alerts and settings rows already separate with border-border; one edge vocabulary is easier to hold than two.

The border takes a pixel of layout on each side and sits inside the radius, so a card's overflow-hidden clips a full-bleed image at the border's inner edge and the corners stay concentric. The avatar group's ring-2 ring-background is not an outline — it is the gap that separates stacked avatars — and stays a ring.

Equal-elevation nesting

Do not nest a bordered card inside another bordered card at the same visual elevation. Group the content with spacing, a divider, or a deliberately different surface role. When a nested region is necessary, its border/radius must communicate hierarchy rather than duplicate the outer container.

Stacking

There is one portal band, z-50, and DOM order decides nesting within it — z-10 remains for a local raise inside a component. The named --z-raised / --z-overlay / --z-toast tokens are gone: OVL-2 is decided as shadcn, and upstream writes z-50 on every portaled surface.

The one exception is the Toast viewport, which sits at z-60 (decision OVL-15, since 0.12.0). DOM order cannot serve it: the viewport mounts with the app provider, before any dialog exists, so on DOM order alone a toast fired from an open dialog would render behind the scrim. One band above z-50 puts it in front of every overlay instead. Nothing else leaves z-50 — do not copy z-60 onto a surface of your own. test/stacking.browser.test.tsx measures the behaviour rather than assuming it.

Do
Separate resting and floating surfaces with border-border, and reserve shadow for surfaces that genuinely float.
Don't
Give a card, a row or a resting control a drop shadow, outline a surface with a ring-* box-shadow, or nest equal-elevation cards.

On this page