A box shadow is written as box-shadow: x-offset y-offset blur spread color, with an optional inset keyword. Soft, realistic shadows usually stack two or three layers with low opacity, and a shadow on the bottom only uses a positive y offset with a negative spread. Pick any of the 40 examples below and copy it as CSS or Tailwind.
| Part | Example | What it does |
|---|---|---|
| x offset | 0 | Moves the shadow right (positive) or left (negative) |
| y offset | 8px | Moves the shadow down (positive) or up (negative) |
| blur radius | 24px | Softens the edge; cannot be negative; 0 is a hard edge |
| spread radius | -6px | Grows (positive) or shrinks (negative) the shadow before blurring |
| color | rgb(0 0 0 / 0.15) | Falls back to the element's text colour when left out |
| inset | inset | Draws the shadow inside the border instead of outside |
Updated
Most shadow lists give you a picture and a line of CSS. This one also explains why a shadow looks real or fake, gives you a matching elevation scale you can drop into a design system, and shows how to keep shadows visible on dark backgrounds. Every example is original and runs live in your browser.
box-shadow: 0 1px 2px rgb(0 0 0 / 0.06);box-shadow: 0 1px 3px rgb(0 0 0 / 0.08), 0 1px 2px rgb(0 0 0 / 0.04);box-shadow: 0 4px 12px rgb(0 0 0 / 0.06);box-shadow: 0 10px 30px rgb(15 23 42 / 0.08);box-shadow: 0 20px 60px rgb(15 23 42 / 0.10);box-shadow: 0 0 0 1px rgb(0 0 0 / 0.05), 0 2px 6px rgb(0 0 0 / 0.05);box-shadow: 0 1px 2px rgb(0 0 0 / 0.12), 0 4px 12px rgb(0 0 0 / 0.08);box-shadow: 0 1px 1px rgb(0 0 0 / 0.08), 0 2px 4px rgb(0 0 0 / 0.08), 0 8px 16px rgb(0 0 0 / 0.08);box-shadow: 0 1px 1px rgb(0 0 0 / 0.06), 0 2px 2px rgb(0 0 0 / 0.06), 0 4px 8px rgb(0 0 0 / 0.06), 0 16px 32px rgb(0 0 0 / 0.06);box-shadow: 0 2px 4px rgb(0 0 0 / 0.06), 0 12px 24px -4px rgb(0 0 0 / 0.12);box-shadow: 0 4px 6px rgb(0 0 0 / 0.05), 0 24px 48px -12px rgb(0 0 0 / 0.25);box-shadow: 0 2px 2px rgb(0 0 0 / 0.04), 0 8px 8px rgb(0 0 0 / 0.04), 0 32px 32px rgb(0 0 0 / 0.06), 0 64px 64px rgb(0 0 0 / 0.08);box-shadow: 0 8px 6px -6px rgb(0 0 0 / 0.3);box-shadow: 0 12px 12px -10px rgb(0 0 0 / 0.25);box-shadow: 0 20px 20px -16px rgb(15 23 42 / 0.35);box-shadow: 0 1px 0 rgb(0 0 0 / 0.08);box-shadow: 0 4px 6px -4px rgb(0 0 0 / 0.15);box-shadow: 0 4px 0 rgb(15 23 42 / 0.9);box-shadow: inset 0 2px 4px rgb(0 0 0 / 0.15);box-shadow: inset 0 1px 3px rgb(0 0 0 / 0.2), inset 0 0 0 1px rgb(0 0 0 / 0.06);box-shadow: inset 0 1px 2px rgb(0 0 0 / 0.08), 0 0 0 3px rgb(79 152 251 / 0.35);box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.6), 0 1px 2px rgb(0 0 0 / 0.15);box-shadow: inset 0 0 40px rgb(0 0 0 / 0.25);box-shadow: inset 0 0 0 2px rgb(15 23 42 / 0.8);box-shadow: 0 8px 24px -6px rgb(79 152 251 / 0.55);box-shadow: 0 10px 30px -8px rgb(124 58 237 / 0.5);box-shadow: 0 12px 24px -10px rgb(244 63 94 / 0.55);box-shadow: 0 10px 25px -10px rgb(16 185 129 / 0.6);box-shadow: 0 0 0 4px rgb(245 158 11 / 0.25), 0 6px 18px rgb(245 158 11 / 0.35);box-shadow: 0 0 8px rgb(34 211 238 / 0.8), 0 0 24px rgb(34 211 238 / 0.4);box-shadow: 0 0 0 1px rgb(255 255 255 / 0.08), 0 8px 24px rgb(0 0 0 / 0.6);box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.08), 0 4px 12px rgb(0 0 0 / 0.5);box-shadow: 0 0 0 1px rgb(148 163 184 / 0.2), 0 0 24px rgb(79 152 251 / 0.25);box-shadow: 0 0 0 1px rgb(255 255 255 / 0.1), 0 24px 64px rgb(0 0 0 / 0.7);box-shadow: 6px 6px 0 rgb(15 23 42);box-shadow: 4px 4px 0 rgb(79 152 251);box-shadow: 0 0 0 2px #fff, 0 0 0 4px rgb(15 23 42);box-shadow: 4px 4px 0 -1px #fff, 4px 4px 0 0 rgb(15 23 42 / 0.3), 8px 8px 0 -1px #fff, 8px 8px 0 0 rgb(15 23 42 / 0.2);box-shadow: 1px 1px 0 rgb(0 0 0 / 0.2), 2px 2px 0 rgb(0 0 0 / 0.18), 3px 3px 0 rgb(0 0 0 / 0.16), 4px 4px 0 rgb(0 0 0 / 0.14), 5px 5px 0 rgb(0 0 0 / 0.12);box-shadow: 0 0 0 1px rgb(15 23 42 / 0.15);A negative spread shrinks the shadow on every side, and the y offset then pushes it out below. Keep the spread close to minus the blur so nothing leaks past the left and right edges.
From left: a tight edge, a softer drop and the thin line used under sticky headers.
<style>
.row { display: flex; gap: 16px; flex-wrap: wrap; padding: 12px }
.row div { width: 120px; height: 80px; background: #fff; border-radius: 10px; border: 1px solid #eee }
.a { box-shadow: 0 8px 6px -6px rgb(0 0 0 / 0.3) }
.b { box-shadow: 0 12px 12px -10px rgb(0 0 0 / 0.25) }
.c { box-shadow: 0 4px 6px -4px rgb(0 0 0 / 0.15) }
</style>
<div class="row"><div class="a"></div><div class="b"></div><div class="c"></div></div>Five steps cover most interfaces. Each one doubles the offset and blur of the last and keeps a tight contact layer underneath.
| Token | Use for | Value |
|---|---|---|
| --shadow-1 | Resting cards, inputs | 0 1px 2px rgb(0 0 0 / .08), 0 1px 3px rgb(0 0 0 / .06) |
| --shadow-2 | Hovered cards | 0 1px 2px rgb(0 0 0 / .06), 0 4px 8px rgb(0 0 0 / .08) |
| --shadow-3 | Dropdowns, popovers | 0 2px 4px rgb(0 0 0 / .06), 0 12px 24px rgb(0 0 0 / .10) |
| --shadow-4 | Drawers, sticky bars | 0 4px 8px rgb(0 0 0 / .06), 0 24px 48px rgb(0 0 0 / .14) |
| --shadow-5 | Dialogs | 0 8px 16px rgb(0 0 0 / .08), 0 40px 80px rgb(0 0 0 / .20) |
Components use var(--shadow-2) and never hard-code a shadow. The dark block swaps in a faint rim plus deeper black.
:root {
--shadow-1: 0 1px 2px rgb(0 0 0 / .08), 0 1px 3px rgb(0 0 0 / .06);
--shadow-2: 0 1px 2px rgb(0 0 0 / .06), 0 4px 8px rgb(0 0 0 / .08);
--shadow-3: 0 2px 4px rgb(0 0 0 / .06), 0 12px 24px rgb(0 0 0 / .10);
--shadow-4: 0 4px 8px rgb(0 0 0 / .06), 0 24px 48px rgb(0 0 0 / .14);
--shadow-5: 0 8px 16px rgb(0 0 0 / .08), 0 40px 80px rgb(0 0 0 / .20);
}
@media (prefers-color-scheme: dark) {
:root {
--shadow-1: 0 0 0 1px rgb(255 255 255 / .06), 0 1px 3px rgb(0 0 0 / .5);
--shadow-3: 0 0 0 1px rgb(255 255 255 / .08), 0 12px 24px rgb(0 0 0 / .6);
--shadow-5: 0 0 0 1px rgb(255 255 255 / .1), 0 40px 80px rgb(0 0 0 / .7);
}
}
.card { box-shadow: var(--shadow-1); transition: box-shadow .2s }
.card:hover { box-shadow: var(--shadow-2) }The left card uses one big blur. The right card spreads the same darkness over three layers, which reads as a softer, more natural lift.
<style>
body { background: #f4f4f5 }
.row { display: flex; gap: 24px; flex-wrap: wrap; padding: 20px }
.row div { width: 130px; height: 100px; background: #fff; border-radius: 14px; display: grid; place-items: center; font-size: 13px }
.one { box-shadow: 0 10px 30px rgb(0 0 0 / .3) }
.three { box-shadow: 0 1px 2px rgb(0 0 0 / .1), 0 4px 8px rgb(0 0 0 / .08), 0 16px 32px rgb(0 0 0 / .08) }
</style>
<div class="row"><div class="one">One layer</div><div class="three">Three layers</div></div>
Real objects cast two kinds of shadow at once: a small dark one right where they touch the surface and a wide pale one from light bouncing around the room. A single blurred shadow tries to be both and ends up looking like a grey halo.
Stacking two to four layers, each with roughly double the offset and blur of the one before and a lower opacity, imitates that mix. The cost is small, but very large blur values on many elements can slow down scrolling on weak devices, so keep heavy shadows to a few raised surfaces.
Products feel consistent when every raised thing picks from a short ladder: resting cards, hovered cards, dropdowns, dialogs. Store each step as a custom property and reuse it, so changing the light direction later means editing one place.
Keep the y offset growing faster than the x offset, which stays at zero for a light source directly above. Mixing light directions across components is one of the quickest ways to make an interface look assembled from parts.
Give the shadow a positive y offset and a negative spread about the same size as the blur, for example box-shadow: 0 8px 6px -6px rgb(0 0 0 / 0.3). The negative spread pulls the shadow in from the left, right and top, so only the part pushed down past the bottom edge shows.
Separate the shadows with commas. The first shadow in the list is painted on top of the others, so put the tight, darker contact shadow first and the wide, faint ambient shadow last.
A black shadow on a near-black page has almost no contrast. In dark themes, lean on a lighter surface colour for raised elements, add a thin light border or a 1px inset highlight, and raise the shadow opacity rather than relying on the shadow alone.
box-shadow follows the element's box and border-radius. filter: drop-shadow() follows the visible pixels, so it hugs transparent PNGs and SVG shapes, but it has no spread value and no inset option.
Use an arbitrary value with underscores in place of spaces, such as shadow-[0_8px_24px_-6px_rgb(0_0_0/0.2)]. The built-in scale runs from shadow-2xs to shadow-2xl, and inset-shadow-sm and friends cover inner shadows.
Related: CSS shadow generator, Text shadow generator, CSS button states, Dark mode for websites, CSS variables guide.
Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.
We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.