Skip to content
SproutAceve · v3.25.1
Get started
Overview What is your role? Connect to Sprout MCP reference Adopting Sprout
Foundations
Brand & logos Color Typography Spacing & layout Elevation Iconography Accessibility
Components
Overview Buttons Inputs & forms Numeric input Data grid Ribbon toolbar Navigation Cards Alert Avatar Badge Dialog Tabs Floating tabs Menu
Practice
Interaction & motion Voice & content Product patterns
Artificial Intelligence
AI patterns AI transparency & disclosure AI disclosure label
People & ethics
Design principles Personas Trust and ethics Meet the makers
Playground
Build the systemplay Tower of tokensplay
Behind the system
How it works Changelogv3.25 Roadmap Contribute
Draft
Foundations

Shadow & elevation.

Four layers, three steps of height. Light mode borrows from print and casts a shadow. Dark mode borrows from physics and brightens the surface instead. The token names are the same in both. Only the mechanism flips.

border + shadow/elevation

Light mode borrows from print. Dark mode borrows from physics.

Light mode
Shadows lift things up.

On a paper white canvas, depth is cast. The higher a surface sits, the softer and longer its shadow. Dialogs and popovers use shadow-floater. Toolbars stay at shadow-surface. Cards never use shadow alone. A hairline border works with it.

shadow-surfaceCard
shadow-overlayDrawer
shadow-floaterDialog
Dark mode
Surfaces brighten as they rise.

In the dark, cast shadows disappear, because there is no light to cast them. So we invert the model: each elevation step lightens the surface. The dialog floats by being brighter than the drawer behind it, not by sitting on a shadow that doesn't exist.

layers/surfaceCard
layers/overlayDrawer
layers/floaterDialog
One API, two mechanisms

The three shadow tokens only render in light mode. In dark mode they resolve to none and the matching layers/* token carries the lift instead. A component declares both once, using background: layers/overlay with box-shadow: Shadow/Overlay, and is correct in either mode with no conditional. The elevation API is the same; the visual mechanism flips.

The three shadow tokens

Three steps, and no more. Overlay and Floater are each two drop shadows: a key shadow that grows with height, and an ambient shadow that keeps the edge anchored. Surface is a single shadow, which is why a card reads as resting rather than floating.

TokenKey shadowAmbient shadowFigma variables
Shadow/Surface0 1px 2px rgba(0,0,0,.06)none
surface/y 1 ·blur 2· #0000000F
Shadow/Overlay0 4px 12px rgba(0,0,0,.10)0 1px 2px rgba(0,0,0,.06)
overlay/y 4 ·blur 12· #0000001A
y-ambient 1 ·blur-ambient 2· #0000000F
Shadow/Floater0 16px 32px rgba(0,0,0,.16)0 4px 8px rgba(0,0,0,.08)
floater/y 16 ·blur 32· #00000029
y-ambient 4 ·blur-ambient 8· #00000014

Offset and blur roughly double at each step (1/2 → 4/12 → 16/32) and opacity rises with them (6% → 10% → 16%). Both moving together is what reads as height rather than as a darker edge. Note that surface/color and overlay/color-ambient both hold #0000000F, so Surface and the quiet half of Overlay are the same shadow under two names.

The four layers

Those three tokens map onto three layers above the page. Same geometry in both modes. On the left the boxes are all white and separated by shadow. On the right they are all shadowless and separated by fill.

Light · separated by shadow
Background
Surface
Overlay
Floater
Dark · separated by fill
Background
Surface
Overlay
Floater
The floater in practice

The plates above keep every layer neutral so the fill ladder stays readable. Most real floaters are not neutral. A FAB is filled, and a filled element carries its own boundary.

Light · primary
+

4.86:1 against the page. No border.

Dark · primary container
+

17.69:1 against the page. No border.

Fills, shadows and the border
Layer
Light
Dark
Step apart
layers/background
Fill
grey/25 #F9F9F9
Shadow
none
Fill
grey/950 #0D0D0D
Shadow
none
The page. Nothing sits at background. It is what the rest sits on, and it never takes a shadow or a border.
layers/surface
Fill
grey/0 #FFFFFF
Shadow
Shadow/Surface
Fill
grey/900 #1A1A1A
Shadow
none
1.05:1 from the page in light, 1.12:1 in dark.
layers/overlay
Fill
grey/0 #FFFFFF
Shadow
Shadow/Overlay
Fill
grey/850 #262626
Shadow
none
1.15:1 above surface in dark. In light the fill is unchanged and the shadow does all of it.
layers/floater
Fill
grey/0 #FFFFFF
Shadow
Shadow/Floater
Fill
grey/800 #333333
Shadow
none
1.20:1 above overlay in dark.
layers/outline-variant
Border
grey/50 #F2F2F2
Border
alpha/white/06
1px on neutral surfaces, both modes. In dark it is their only boundary, since the shadow is inert. The test: if a layer's own fill already reaches 3:1 against what is behind it, it needs no border.

Exactly one thing varies per mode: light varies the shadow and holds the fill at white, dark varies the fill and holds the shadow at none. The border is constant in both.

What belongs on each layer

Pick the layer by how the thing relates to the page, not by how important it is. Importance is the most common reason to reach one step too high.

Layer 0Backgroundno shadow · no border

The page canvas, and any full bleed region that reads as the page: a scroll container, an empty state, a section band.

Layer 1SurfaceShadow/Surface

Anything that sits in the layout flow: cards, list rows, table containers, accordions, inline panels, toolbars, app bars and tab bars.

Layer 2OverlayShadow/Overlay

Anchored to a trigger and dismissed by clicking away: drawers, bottom sheets, dropdown and select menus, popovers, date pickers, autocomplete.

Layer 3FloaterShadow/Floater

Detached from the layout with no anchor, or persistent above it: dialogs and modals, toasts, tooltips, the FAB, floating tabs.

Elevation and z-index rank differently

A dropdown is overlay in elevation but z-index/dropdown 900, above z-index/dialog 800, because a select inside a dialog has to render above it. Elevation describes visual height, z-index resolves stacking. That is correct, so don't align them.

Nesting stops the ladder

The ladder applies to layers that sit on the page. Inside a raised container it stops: a card in a drawer keeps the drawer's fill and separates with the hairline alone.

In dark mode a card that held its own layers/surface fill inside an overlay drawer would be darker than the drawer, reading as a hole rather than as something raised. In light mode the equivalent mistake is a second shadow, which reads as two heights at once. Either way the container has already established the height; the things inside it only need separating from each other.

Do & Don't

Four decisions that come up every time someone builds at one of these layers.

✓ Do
Keep the hairline on neutral surfaces.

Their fill is 1.05:1 from the page in light and 1.12:1 in dark, so the border is the only edge they have when the shadow is inert.

✗ Don't
+
Don't put the hairline on a filled element.

A primary FAB is already 4.86:1 from the page, so its fill is the boundary. outline variant over it lands at 4.57:1, which reads as a bright ring, not a soft edge.

✓ Do
background: layers/overlaybox-shadow: Shadow/Overlay
Take the fill and the shadow from the same layer.

layers/overlay with Shadow/Overlay. Both modes then resolve correctly with no conditional.

✗ Don't
Shadow/SurfaceShadow/Surface-plusShadow/Overlay
Don't invent a step between two tokens.

Three is the whole scale. If something seems to need a fourth, it is on the wrong layer.

✓ Do
Stop the ladder inside a raised container.

A card in a drawer keeps the drawer's fill and separates with the hairline alone. The container already established the height.

✗ Don't
Don't stack shadows.

A raised thing inside a raised thing composites to a height neither token describes, and in dark it inverts into a hole.

✓ Do
Let the fill carry it in dark mode.

Each step lightens the surface. That is the whole elevation signal once the shadow stops working.

✗ Don't
Don't rely on the shadow in dark mode.

It is declared, and it is inert. There is no light on a near black page for a shadow to remove.

← PreviousSpacing & layoutNext →Iconography
Sprout · Aceve Design System · v3.25.1
Figma library GitLabReleases