Elevation
The seven shadows Propel ships, what each one lifts, and where depth comes from instead.
Propel ships 7 shadows in three groups: raised for things that lift within the
page, overlay for things that float above it, and direction for panels that cast sideways.
<div class="rounded-lg bg-surface-1 shadow-overlay-100">…</div>
Shadow is the smaller half of the depth system. Only 13 component families cast one directly, alongside 4 shared internal surfaces; everything else separates itself with a 1px border and a step on the surface ladder. Reach for the ladder first, and add a shadow only when an element genuinely leaves the layout.
Raised
On-surface lift for controls and cards that stay in the layout. The shallowest tier — a raised element is still part of the page, not floating above it.
shadow-raised-100
The subtlest lift. Controls that sit in flow and need an edge without looking detached.
- layer 1
- 0px 1px 6px -1px rgb(41 47 61 / 0.03)
- layer 2
- 0px 1px 4px 0px rgb(41 47 61 / 0.04)
- used by
- button-group, internal/control-chrome, number-field, slider, switch, toggle
shadow-raised-200
A tighter, slightly darker lift for a surface that overlaps its neighbours.
- layer 1
- 0px 1px 2px -1px rgb(41 47 61 / 0.06)
- layer 2
- 0px 1px 3px 0px rgb(41 47 61 / 0.05)
- used by
- tabs
shadow-raised-300
The deepest in-flow lift — hover-lifted cards and trigger surfaces.
- layer 1
- 0px 2px 4px -1px rgb(41 47 61 / 0.04)
- layer 2
- 0px 4px 6px -1px rgb(41 47 61 / 0.05)
- used by
- alert-dialog, dialog
Overlay
Floating layers that sit above the page and take focus with them. Pair with a real surface color — a shadow alone doesn't separate an overlay from what's behind it.
shadow-overlay-100
Dropdowns, selects, popovers, drawers — anything anchored to a trigger.
- layer 1
- 0px 10px 10px -5px rgb(41 47 61 / 0.04)
- layer 2
- 0px 10px 40px -5px rgb(41 47 61 / 0.04)
- used by
- internal/listbox-popup, internal/popup-surface, internal/surface, preview-card
shadow-overlay-200
The deepest shadow in the system, for the modal layer. Its 60px second blur is what separates a dialog from the whole page beneath it.
- layer 1
- 0px 10px 10px -10px rgb(41 47 61 / 0.04)
- layer 2
- 0px 30px 60px -12px rgb(41 47 61 / 0.1)
- used by
- internal/surface, popover, preview-card, tooltip
Directional
Side-anchored panels casting onto the content they cover. Horizontal offset only, no vertical component — these read as a panel edge, not as height.
shadow-direction-left
A panel or sticky column casting toward the inline-start edge.
- layer 1
- -10px 0px 30px -5px rgb(41 47 61 / 0.02)
- layer 2
- -5px 0px 80px -5px rgb(41 47 61 / 0.04)
- used by
- drawer, table
shadow-direction-right
The mirror, casting toward the inline-end edge.
- layer 1
- 10px 0px 30px -5px rgb(0 0 0 / 0.04)
- layer 2
- 5px 0px 80px -5px rgb(0 0 0 / 0.04)
- used by
- drawer, table
What the reset removes
--shadow-*: initial clears Tailwind’s scale before Propel declares its own, so every utility below
generates no CSS and fails silently. The bare shadow goes with them, since it read --shadow.
There is no replacement: a shadow should come from the three groups above, chosen by what the
element is rather than by how heavy it should look.
Three things survive. shadow-none is a static utility rather than a token, so it still cancels an
inherited shadow. inset-shadow-* and drop-shadow-* are separate namespaces Propel never touches,
so Tailwind’s defaults apply unchanged — they carry a generic pure-black tint rather than Propel’s
slate ink, and will look subtly foreign beside the tokens above.
Guidelines
A shadow alone does not separate a floating layer from the page; it darkens the edge of something
that still shows whatever is behind it. Pair every overlay with a real background, as
bg-surface-1 shadow-overlay-100, and never ship the shadow on its own.
Shadows don’t compose. Two elevated surfaces nested inside each other produce overlapping ambient layers that read as a smudge rather than as two levels, so let the outer layer carry the shadow and give the inner one a border.
Elevation says an element sits on a layer above, not that it is interactive. Hover and pressed states belong to the surface and border tokens, and a control that lifts on hover is claiming to float, which almost nothing in Propel does.
Stacking order is a separate concern again. Propel declares no z-index tokens, and a deeper shadow
does not put an element in front of anything.
Theme behavior
All seven shadows are declared once, outside every theme selector, so the same ink renders in light, dark, light-contrast, and dark-contrast.They are tuned for a light canvas, using slate ink rgb(41 47 61) at 2–10% alpha, which is close to
invisible against a dark background. That is not a bug to route around with a heavier shadow. In
dark themes depth comes from the surface ladder and borders, and the shadow quietly stops
contributing.
One shadow breaks the pattern: shadow-direction-right is tinted pure black rather than slate ink,
the only one in the system that is. It reads as an inconsistency rather than a decision.