Propel

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.

Each one is a two-layer shadow: a tight contact layer that grounds the edge, and a wide ambient layer that does the lifting.
<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.

RemovedTailwind's value
shadow-2xs0 1px rgb(0 0 0 / 0.05)
shadow-xs0 1px 2px 0 rgb(0 0 0 / 0.05)
shadow-sm0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)
shadow-md0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)
shadow-lg0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)
shadow-xl0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)
shadow-2xl0 25px 50px -12px rgb(0 0 0 / 0.25)
shadow-innerinset 0 2px 4px 0 rgb(0 0 0 / 0.05)

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.