#ui-design

Box Shadow Elevation Scale: 5 Copy-Ready Levels for UI

A single copy-pasted box-shadow value doesn't communicate depth. It just decorates. Here is a 5-level elevation scale you can copy, and how to use it.

··7 min read
Box Shadow Elevation Scale: 5 Copy-Ready Levels for UI

The usual way shadow gets added to an interface: one box-shadow value, copy-pasted onto every card, dropdown, and modal in the product. It's an easy habit, and it's also why shadow so often reads as decoration instead of doing what it's supposed to do: telling the user what's sitting above what.

Quick answer: a 5-level box shadow scale

A ready-to-use elevation scale for a light interface. Each level is two layered shadows, and each one is larger and softer than the last:

LevelUse it forbox-shadow
0Flat page surfacesnone
1Cards and panels at rest0 1px 2px rgba(15,23,42,.06), 0 1px 3px rgba(15,23,42,.10)
2Hovered cards, raised buttons0 2px 4px -1px rgba(15,23,42,.06), 0 4px 8px -2px rgba(15,23,42,.10)
3Dropdowns, popovers, menus0 4px 6px -2px rgba(15,23,42,.05), 0 12px 20px -4px rgba(15,23,42,.12)
4Modals, dialogs, drawers0 8px 12px -4px rgba(15,23,42,.06), 0 24px 40px -8px rgba(15,23,42,.16)
5Toasts, dragged items0 12px 16px -6px rgba(15,23,42,.08), 0 32px 64px -12px rgba(15,23,42,.22)

Want to tune these for your own design? Build and preview a full elevation scale in the Shadow Builder.

What shadow is actually for

In a real environment, an object closer to the light source, and further from the surface behind it, casts a bigger, softer shadow than one resting flat against that surface. Interfaces borrow this because it's an intuitive way to communicate layering. A modal floating over a page should look further up than a card sitting flat inside it. A single fixed shadow value can't express that difference. Every layer ends up looking like it's at the same height, which quietly undermines the hierarchy shadow was supposed to create.

Build an elevation scale, not one shadow

The fix follows the same pattern as color, type, radius, and spacing: a small set of levels instead of one value. Five levels, plus a flat level 0, cover almost every interface:

  • Levels 1–2, resting and raised: cards in the normal page flow, and the same cards when hovered. Small blur, low opacity.
  • Level 3, floating: dropdowns, popovers and menus that open on top of the page. Noticeably larger blur and offset.
  • Levels 4–5, overlays: modals, drawers, toasts and anything being dragged. The largest, softest shadows, clearly detached from the page behind.

As elevation increases, the shadow should get larger and softer rather than simply darker. A bigger, more diffuse shadow is what actually reads as further away. A darker but tight shadow just reads as heavier.

Before and after: a card, a dropdown and a modal all using the same shadow so they look equally high, next to the same three using elevation levels 1, 3 and 4 so the modal clearly floats highest.
Left: one shadow on everything, so the card, dropdown and modal all look the same height. Right: levels 1, 3 and 4, so each layer reads at its own height.

Layer shadows instead of using one

A single box-shadow tends to look flat and a bit synthetic. Real shadow is a blend: a tight, darker shadow close to the object (a contact shadow) plus a larger, softer one further out (an ambient shadow). CSS lets you stack both in one declaration, separated by a comma:

  • box-shadow:
  •   0 2px 4px -1px rgba(15,23,42,.06), /* contact */
  •   0 4px 8px -2px rgba(15,23,42,.10); /* ambient */

The negative spread value (the -1px and -2px) pulls each shadow in slightly, so it sits under the element instead of leaking out the sides. Every level in the scale above uses this two-layer pattern.

Two cards compared: one with a single flat shadow, one with a tight contact shadow plus a soft ambient shadow that looks more natural.
One shadow (left) looks pasted on. A tight contact shadow plus a soft ambient shadow (right) looks like the card is really sitting above the page.

Keep the light source consistent

Shadows should all fall in the same direction, typically straight down or down and slightly to one side, across every component in the product. Mixing directions, one component's shadow falling down-right, another's falling straight down, reads as inconsistency even to someone who can't say why it looks wrong. Pick one light direction for the whole system and keep every level of the scale consistent with it.

Elevation changes with interaction

Elevation isn't fixed per component; it also tells the user what's happening:

  • Hover: lift a clickable card one level (1 → 2). It signals "this responds to you."
  • Press: drop it back down (2 → 1), as if it's being pushed into the page.
  • Drag: use the highest level (5) while an item is being moved, so it clearly sits above everything else.

Only lift things that are interactive. A static card that rises on hover promises a click that never comes.

Shadows in dark mode

On a dark background, a dark shadow has almost nothing to contrast with, so elevation disappears. Two adjustments fix it:

  • Lighten the surface as it rises. Higher layers get a slightly lighter background than the page (for example, page #0f172a, card #1e293b, modal #273449). This does most of the work.
  • Make the shadow stronger, not bigger. Raise the opacity (around 0.3–0.5) so the shadow still reads at the edges.

Where it usually breaks down

Too dark or too opaque is the most common issue: a heavy, high-opacity shadow reads as harsh rather than elevated. Real shadows are diffuse and fairly light; low opacity, 10 to 20 percent, usually looks more natural than it seems like it should. The same shadow on every layer is the other common one. If cards, dropdowns, and modals all use the same value, elevation stops communicating anything, since everything looks like it's floating at the same height. And shadow chosen without radius in mind tends to look unfinished; a soft, diffuse shadow around a sharp-cornered element reads as a mismatch rather than a design choice.

Turn the scale into CSS tokens

Define the scale once as CSS custom properties, then reference it everywhere:

  • --shadow-1: 0 1px 2px rgba(15,23,42,.06), 0 1px 3px rgba(15,23,42,.10);
  • --shadow-2: 0 2px 4px -1px rgba(15,23,42,.06), 0 4px 8px -2px rgba(15,23,42,.10);
  • --shadow-3: 0 4px 6px -2px rgba(15,23,42,.05), 0 12px 20px -4px rgba(15,23,42,.12);
  • --shadow-4: 0 8px 12px -4px rgba(15,23,42,.06), 0 24px 40px -8px rgba(15,23,42,.16);
  • --shadow-5: 0 12px 16px -6px rgba(15,23,42,.08), 0 32px 64px -12px rgba(15,23,42,.22);

Components then use box-shadow: var(--shadow-3) instead of a hand-typed value. When AI coding tools write your interface, named tokens like these stop them from inventing a new shadow for every component.

Shadow and radius are a pair

Elevation and rounding are the same underlying concern, how a surface separates from what's behind it, and work better designed together than as two unrelated settings. See border-radius in UI design, or set both up in one place with the Design Language Studio, where radius and shadow are handled as a single surface-treatment step.

To build and preview an elevation scale, and export it as CSS, Tailwind or rules for AI coding tools, use the Shadow Builder.

Box shadow FAQ

How many shadow levels does a design system need?

At least three (resting, floating, overlay), and rarely more than six. Five levels plus a flat level 0 covers cards, hover states, dropdowns, modals and toasts without leaving designers guessing between near-identical options.

Should box shadows be pure black?

Usually not. Pure black at low opacity can look grey and dirty. A very dark, slightly blue-grey (like rgba(15,23,42,…)) or a dark tint of your brand color looks cleaner and more natural.

What opacity should a box shadow have?

On light backgrounds, 5–20% per layer. Lower levels sit around 6–10%, the highest around 20%. If a shadow looks like a dark outline, the opacity is too high or the blur too small.

What's the difference between box-shadow and filter: drop-shadow?

box-shadow follows the element's box, including its border radius, and is what you want for cards, buttons and modals. filter: drop-shadow() follows the actual visible shape, so use it for transparent PNGs, SVG icons and irregular shapes.