Role-based shadow tokens and how Box, Card, and popup surfaces apply them.
@prepared911/ui/styles.css as --elevation-* custom properties (vendored from Chroma). React exposes the five Box roles through Elevation on Box and FlexBox. Card uses CardElevation for its optional resting shadow.
Values below are copied from system.css. Shadow lengths that use calc(1rem * …) assume the document root is 16px (1rem), matching the rest of the token scale.
| Role | Elevation | Token | Light (:where(:root)) | Dark ([data-theme='dark']) | Typical use | Consumers in @prepared911/ui |
|---|---|---|---|---|---|---|
| Flat | None | — | none | none | List rows, dense tables, chrome with no lift | Default Box / Card |
| Sunken | Sunken | --elevation-sunken-shadow | inset 0 1px 2px 0 var(--elevation-xs-color) | same shape; --elevation-xs-color is rgba(0,0,0,0.20) | Inset wells and recessed tracks | Box / FlexBox elevation only |
| Raised | Raised | --elevation-raised-shadow | 0 1px 2px 0 var(--elevation-md-color) | same shape; --elevation-md-color is rgba(0,0,0,0.24) | Cards and panels resting on the page | Box, Card (CardElevation.Raised), Popover, Accordion, ChannelList (raised chip) |
| Overlay | Overlay | --elevation-overlay-shadow | 0 4px 8px 0 var(--elevation-md-color) | same shape | Tooltips, compact popups, chat chrome | Box, Tooltip, ChatInput, ChannelList (overlay panel), ChartFrame tooltip, popup-surface-overlay recipe |
| Modal | Modal | --elevation-modal-shadow | 0 8px 16px 0 var(--elevation-md-color) | same shape | Blocking dialogs and modal shells | Box, Dialog (modal-surface recipe), popup-surface-modal recipe |
Box Elevation value; components reference it in CSS.
| Token | Light | Dark | Typical use | Consumers |
|---|---|---|---|---|
--elevation-floating-shadow | 0 20px 48px 0 var(--elevation-soft-color-105), 0 3px 10px 0 var(--elevation-soft-color-045) | 0 22px 55px 0 var(--elevation-soft-color-340) | Large floating trays above the page | Menu, Listbox, Toast, Toolbar (floating variant), ChatScroll jump control, Select / Combobox list surfaces |
| Token | Purpose | Consumers |
|---|---|---|
--elevation-resting-shadow | Selected pill in segmented controls | SelectionPill (used by SegmentedControl, ToggleGroup) |
--elevation-thumb-shadow | Switch and slider thumbs | SwitchTrack, Switch, Slider |
--elevation-bubble-shadow | Slider value bubble (dark theme region) | SliderBubble |
| Token | Light | Dark |
|---|---|---|
--elevation-xs-color | rgba(0,0,0,0.07) | rgba(0,0,0,0.20) |
--elevation-sm-color | rgba(0,0,0,0.20) | rgba(0,0,0,0.22) |
--elevation-md-color | rgba(0,0,0,0.22) | rgba(0,0,0,0.24) |
--elevation-lg-color | rgba(0,0,0,0.24) | rgba(0,0,0,0.26) |
--elevation-xl-color | rgba(0,0,0,0.28) | rgba(0,0,0,0.28) |
--elevation-soft-color-* steps in system.css back --elevation-resting-shadow, --elevation-floating-shadow, thumb, and bubble tokens.
Pass elevation={Elevation.<Role>}. Background stays on background; elevation only sets box-shadow.
CardElevation.None (default) keeps a Surface card flat. CardElevation.Raised adds --elevation-raised-shadow on CardVariant.Surface only; Ghost accepts None at the type level.
tailwind/recipes/popup-surface.css and modal-surface.css. Use @apply in colocated component CSS, not ad hoc utility strings in className (see Portal usage).
popup-surface-shell: border, radius, overlay fill, motion hooks; under forced-colors: active, border color becomes CanvasText.popup-surface-overlay: shell + --elevation-overlay-shadow.popup-surface-modal: shell + --elevation-modal-shadow.modal-surface: shell + modal motion + --elevation-modal-shadow (Dialog).Drawer paints one of four edge tokens on the sliding panel:
| Token | Applied on |
|---|---|
--elevation-drawer-inline-start-shadow | inlineStart panel (leading inline edge) |
--elevation-drawer-inline-end-shadow | inlineEnd panel |
--elevation-drawer-block-start-shadow | blockStart panel |
--elevation-drawer-block-end-shadow | blockEnd panel |
block-start casts down from a top-anchored panel and block-end casts up from a bottom-anchored panel.
Listbox paints --elevation-drawer-block-end-shadow on a pinned footer divider when footerShadow is enabled.
On the default dark theme, shadows are subtle against --color-bg-default; pair raised surfaces with BorderColor.Subtle or BorderColor.Default when fill and page are close in value.
Under forced-colors: active, system colors replace token fills and shadows no longer carry the edge. Shared popup shells keep a 1px border-style: solid edge (popup-surface-shell uses var(--border-width-default) and var(--color-border-default); forced colors switch the border to CanvasText). Surfaces that normally rely on shadow alone should still expose a border in that mode (Toast clears box-shadow and keeps a CanvasText border; Tooltip adds a CanvasText border).
Elevation is not a focus indicator. Pair interactive surfaces with the focus-ring recipes.
Elevation does not replace z-index. Portaled chrome still uses --z-index-* tokens. Band order for overlays (bottom → top): overlay → modal → popover → tooltip. .pr-tooltip sits at calc(var(--z-index-tooltip) + 100) so tooltips paint above popovers when those tokens share a numeric value.
Do
Elevation from the surface role (sunken well, raised card, overlay menu, modal dialog).CardElevation.Raised only on CardVariant.Surface.popup-surface-* and modal-surface recipes in component CSS.--shadow-1…--shadow-5 or Elevation.Low / Medium / High; they are removed.