Zitly logo
Zitly
6 output formats · Free · No signup

Box shadow generator for a full CSS elevation scale

Most CSS shadow generators give you one shadow. This one builds three to ten, grown from a few simple rules, so your cards, menus, and dialogs share one depth system. Tune blur, spread, opacity, and offset, test light and dark backgrounds, then copy code for CSS, Tailwind, React Native, text-shadow, or drop-shadow.

The scale is calculated in your browser as you move the sliders. Nothing you enter is uploaded. The output uses standard CSS, so it works in any framework.

Last updated September 28, 2026

See Tailwind and React Native code
3–10
Elevation levels
4
Starter presets
6
Copy-ready formats

CSS box shadow generator tool

Build your shadow scale

Every change updates the preview and the code below.

Presets

Number of levels

Blur
2px
×4

How quickly blur opens up from level to level

Spread
0px

Negative values tuck the shadow under the element

0px/level
Opacity
14%
+4%

Total added between the first and last level

Offset
0px
1px
2px/level

Live elevation preview

Level 1
Level 2
Level 3
Level 4
Level 5
Level 6
LevelBlurSpreadOpacityYSuggested use
L12px0px14%1pxCards, list items
L26px0px15%3pxMenus, dropdowns
L314px0px16%5pxBetween roles
L426px0px16%7pxPopovers, toasts
L542px0px17%9pxDrawers, side panels
L662px0px18%11pxDialogs, modals

CSS custom properties and utility classes

:root {
  --shadow-1: 0px 1px 2px 0px rgba(0, 0, 0, 0.14);
  --shadow-2: 1px 3px 6px 0px rgba(0, 0, 0, 0.148);
  --shadow-3: 2px 5px 14px 0px rgba(0, 0, 0, 0.156), 1px 2px 6px 0px rgba(0, 0, 0, 0.062);
  --shadow-4: 3px 7px 26px 0px rgba(0, 0, 0, 0.164), 1px 2px 10px 0px rgba(0, 0, 0, 0.066);
  --shadow-5: 4px 9px 42px 0px rgba(0, 0, 0, 0.172), 1px 3px 17px 0px rgba(0, 0, 0, 0.069);
  --shadow-6: 5px 11px 62px 0px rgba(0, 0, 0, 0.18), 2px 3px 25px 0px rgba(0, 0, 0, 0.072);
}

/* Utility classes */
.shadow-elevation-1 { box-shadow: var(--shadow-1); }
.shadow-elevation-2 { box-shadow: var(--shadow-2); }
.shadow-elevation-3 { box-shadow: var(--shadow-3); }
.shadow-elevation-4 { box-shadow: var(--shadow-4); }
.shadow-elevation-5 { box-shadow: var(--shadow-5); }
.shadow-elevation-6 { box-shadow: var(--shadow-6); }

Five steps to a consistent shadow system

You can finish a first pass in about three minutes.

  1. Pick a preset

    Start from Material Design, Soft UI, Sharp Depth, or Glow. Each preset sets every slider, so you begin with a working scale instead of a blank one.

  2. Set the shadow color

    Use black for neutral depth, or a darkened tint of your surface color for a softer look. The preview updates as soon as you enter a valid 6-digit hex value.

  3. Shape the curves

    Adjust blur, spread, opacity, and offset growth. Change one curve at a time and compare the first and last levels in the preview, because they show the full range.

  4. Check light and dark backgrounds

    Switch the preview background. If the low levels disappear on dark, plan a dark-mode override before you ship.

  5. Copy the code

    Choose CSS variables, Tailwind v4, Tailwind v3, React Native, text-shadow, or drop-shadow output, then paste the block into your project.

How a CSS box-shadow value works

Every box-shadow is a short list of values. Once you know what each one does, the sliders above stop feeling like guesswork.

box-shadow: offset-x offset-y blur-radius spread-radius color;
box-shadow: 0px 4px 12px -2px rgba(0, 0, 0, 0.16);
ValueWhat it doesIn practice
offset-xMoves the shadow right (positive) or left (negative).Keep it at 0 for light from directly above. Use small values for a side light source.
offset-yMoves the shadow down (positive) or up (negative).This carries most of the depth. A raised element usually needs a larger Y than X.
blur-radiusSoftens the edge. It cannot be negative.Higher blur reads as more distance from the surface. It is the main difference between levels.
spread-radiusGrows or shrinks the shadow before blur is applied.Small negative values pull the shadow in under the element, which avoids a halo on the sides.
colorSets the shadow color and its alpha.Prefer rgba or a tinted color at 8 to 20% alpha over solid black.
insetDraws the shadow inside the box.Good for pressed buttons and text fields. Text-shadow and drop-shadow do not support it.

You can stack several shadows in one declaration by separating them with commas. The first shadow sits on top. Designers use this to combine a tight key shadow with a wide ambient one, which is what the layered option in the generator does.

Box shadow, drop shadow, or text shadow?

The three properties look similar but follow different shapes. Pick by what the shadow should trace.

PropertyFollowsSpreadInsetBest for
box-shadowThe element box and its border-radiusYesYesCards, buttons, inputs, menus, modals
filter: drop-shadow()The visible pixels, including transparencyNoNoPNG and SVG icons, clipped or irregular shapes
text-shadowThe shapes of the lettersNoNoText over images, headings with a soft glow

When drop-shadow wins

A transparent PNG logo or an SVG icon has no visible box, so box-shadow draws a rectangle around empty space. drop-shadow traces the actual shape. It also works on a parent whose child is clipped with clip-path, where box-shadow gets cut off.

When text-shadow helps

White headings on a photo often lose contrast. A soft, low-opacity text-shadow behind the letters lifts them without adding an overlay. Keep the blur small so the text stays sharp. The text-shadow tab above converts your scale into matching values.

Why one scale beats one-off shadows

Elevation is the sense that some parts of an interface sit higher than others. A raised element casts a bigger, softer, lower shadow. In a real product, the trouble starts when each developer copies a different value. After a year you have a dozen unrelated shadows, and a tooltip can end up looking heavier than the dialog behind it.

A scale fixes this by turning shadows into a short ladder of tokens. The generator grows blur on a curve, so it opens faster at higher levels, and lets opacity, spread, and offset grow at their own rates. Four to six levels cover almost every interface.

Which level goes on which component

ComponentLevel (6-level scale)Reason
Resting card, list itemL1–L2A gentle lift. Pair it with a 1px border on white surfaces.
Hovered cardOne above restThe jump signals the element is interactive.
Sticky headerL2–L3Needs to separate from scrolling content without dominating it.
Dropdown, select menuL3–L4Floats over content but stays below dialogs.
Tooltip, popoverL3–L4Same tier as menus. A tooltip must never look higher than the dialog it sits inside.
ToastL4–L5Must stand out from the page but should not compete with a modal.
Drawer, side panelL5Large surface, so a wide soft shadow works better than a tight one.
Dialog, modalTop levelHighest layer in the interface. Pair it with a dimmed backdrop.

Layered shadows in plain terms

Real light produces two effects: a sharp shadow right under the object and a wide, faint one around it. A single CSS shadow cannot do both. Two shadows stacked in one declaration can. Turn on Layered shadows and compare level 4 with the option off. The difference is usually easy to see on a white surface.

Opacity growth is a judgment call

Some systems keep the same opacity at every level, because more blur already spreads the shadow thin. Others raise opacity a little so high levels still register. Start with a small growth. If level 6 looks washed out, add more. If it looks heavy, set growth to zero.

Move an existing codebase to shadow tokens

Use this checklist on a real project.

grep -rhoE "box-shadow:[^;]+" src/ | sort | uniq -c | sort -rn
  1. Run the search command above to list every box-shadow value in your codebase. Most teams find 10 or more unique values.
  2. Group them by the role of the component: resting, raised, floating, overlay.
  3. Generate a scale here with the same number of groups, and pick the preset closest to your current look.
  4. Replace each raw value with a token. Review one component family at a time so visual changes stay easy to spot.
  5. Add a review rule: new shadows must use a token. This keeps the scale intact after launch.

Six shadow mistakes and how to fix them

These come up again and again in code reviews.

A parent with overflow: hidden clips the shadow

The shadow is drawn outside the element box, so any ancestor that clips overflow cuts it off. This is the most common reason a shadow looks broken.

Add padding to the clipping parent equal to the blur plus offset, or move overflow: hidden to an inner wrapper.

Solid black at high opacity

A 40% black shadow looks dirty on white and heavy on tinted surfaces. It also makes every card feel the same weight.

Stay between 8% and 20% for most levels. Tint the color toward your surface hue for a cleaner result.

One shadow for every component

When a card, menu, and dialog share a shadow, users lose the sense of which layer is on top.

Assign levels by stacking order. Anything that opens above something else gets a higher level.

Animating box-shadow directly

Each animation frame repaints the element. On a list of 30 cards, hover effects can drop frames.

Put the target shadow on a pseudo-element and animate its opacity. The example in the performance section shows how.

Using a shadow as the only edge on inputs

A faint shadow rarely reaches the 3:1 contrast WCAG asks for on the boundary of an interface component.

Give inputs a real border. Use the shadow as extra depth, not as the outline.

Never checking dark mode

Dark shadows on a dark surface disappear, so the interface goes flat and layers merge.

Override the shadow variables under a dark selector. The dark mode section lists three approaches.

Making shadows work in dark mode

A dark shadow needs a lighter surface to show against. On a dark background, the same values that look right on white almost vanish. Use the Dark preview button in the tool to see this for yourself, then pick one of these approaches.

Raise the opacity

Move from about 14% to 30 to 50%. It is the fastest fix and keeps your markup unchanged.

Lighten higher surfaces

Make each level a slightly lighter shade of the base surface. Depth then comes from color, and the shadow only adds definition.

Switch to a glow

Use a tinted, centered shadow for accent elements such as primary buttons. It reads well on dark surfaces.

Because the tool outputs CSS variables, the override is a few lines:

:root {
  --shadow-2: 0px 3px 6px 0px rgba(0, 0, 0, 0.14);
}

@media (prefers-color-scheme: dark) {
  :root {
    --shadow-2: 0px 3px 6px 0px rgba(0, 0, 0, 0.5);
  }
}

Use your shadow scale in CSS, Tailwind, or React Native

The snippets below use sample values. Your generated code fills in the real numbers.

CSS variables (any stack)

Paste the :root block into your global stylesheet, then reference the tokens. Rebranding becomes a one-file change.

.card     { box-shadow: var(--shadow-2); }
.menu     { box-shadow: var(--shadow-4); }
.dialog   { box-shadow: var(--shadow-6); }

Tailwind CSS v4

Put the @theme block in your main CSS file. Tailwind turns each --shadow-elevation-N variable into a utility class.

@import "tailwindcss";

@theme {
  --shadow-elevation-2: 0px 3px 6px 0px rgba(0, 0, 0, 0.16);
}

/* <div class="shadow-elevation-2">…</div> */

Tailwind CSS v3

Merge the boxShadow object into theme.extend. Extending, rather than replacing, keeps the default shadow-md and shadow-lg classes.

// tailwind.config.js
theme: {
  extend: {
    boxShadow: {
      "elevation-2": "0px 3px 6px 0px rgba(0, 0, 0, 0.16)",
    },
  },
}
// <div className="shadow-elevation-2">…</div>

React Native

iOS reads shadowColor, shadowOffset, shadowOpacity, and shadowRadius. Android reads elevation. Set both, and test on a real Android device.

import { shadows } from "./shadows"

<View style={[styles.card, shadows.elevation2]} />

Converting CSS shadows to React Native

The CSS blur radius is roughly twice the iOS shadowRadius, so the generator halves it. Spread has no equivalent in these props, and only the primary layer is exported. Android ignores the iOS props and draws its own shadow from elevation, so the exported elevation numbers are a starting point. Recent React Native versions also accept a CSS-style boxShadow prop. Check the documentation for your version before relying on it.

Keep shadows fast and stable

Shadows cannot cause layout shift

A box-shadow takes up no layout space, so changing or adding one never moves surrounding content. CLS problems near cards usually come from images or fonts, not shadows.

Animate opacity, not the shadow

Changing box-shadow forces a repaint on every frame. Fading a pseudo-element that already carries the final shadow is cheap and keeps interactions responsive.

Watch blur on long lists

Large blur radii cost more to paint. On virtualized lists with many cards, keep the blur modest and profile in your browser performance panel before shipping.

Respect reduced motion

Wrap shadow transitions in a prefers-reduced-motion check so people who turn off animation do not see them.

A hover elevation that animates opacity instead of box-shadow:

.card {
  position: relative;
  box-shadow: var(--shadow-1);
}
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: var(--shadow-4);
  opacity: 0;
  transition: opacity 150ms ease;
  pointer-events: none;
}
.card:hover::after { opacity: 1; }

Choosing a starting preset

Every preset is a set of slider values. Change them freely after you pick one.

Material Design

Neutral, layered, and realistic.

Dashboards, admin tools, and any product where depth should feel natural and quiet.

Soft UI

Tinted, offset, and rounded.

Consumer apps and marketing pages with pastel or tinted surfaces.

Sharp Depth

Tight and high contrast.

Dense interfaces, data tables, and designs with crisp borders.

Glow

Centered and colored.

Dark themes, primary buttons, and status highlights.

CSS shadow questions, answered

Direct answers on box-shadow, drop-shadow, Tailwind, React Native, and dark mode.

A CSS box shadow generator lets you adjust offset, blur, spread, and color with sliders and copy the resulting box-shadow value. This one goes further: it builds a whole scale of 3 to 10 related shadows, so every card, menu, and dialog in your interface shares one depth system.

box-shadow draws around an element's rectangular box and follows its border-radius. filter: drop-shadow() follows the visible shape, including transparent areas in a PNG or SVG. text-shadow follows the letter shapes. Only box-shadow supports spread and inset.

Most products need four to six. That covers resting cards, raised menus, popovers, drawers, and modals. Ten levels rarely produce differences people can see, and they make it harder for a team to choose the right one.

In Tailwind v4, paste the @theme block into your CSS file and use classes like shadow-elevation-3. In Tailwind v3, merge the boxShadow object into theme.extend in tailwind.config.js. The generator produces both formats.

Map the values to shadowColor, shadowOffset, shadowOpacity, and shadowRadius for iOS, and add an elevation number for Android. As a rule of thumb, shadowRadius is about half the CSS blur. Spread has no equivalent in these props. Newer React Native versions also accept a CSS-style boxShadow prop, so check your version.

A parent with overflow: hidden, auto, or scroll clips anything drawn outside its box, including shadows. Add padding to the parent so the shadow has room, or move the overflow rule to an inner wrapper.

Static shadows are cheap. Animating box-shadow forces a repaint on every frame, and large blur values make each repaint slower. For hover effects, put the target shadow on a pseudo-element and animate its opacity instead. Shadows take up no layout space, so they never cause layout shift.

Dark surfaces hide dark shadows. Raise shadow opacity, lighten the surface color of higher levels, or both. Define shadows as CSS variables so you can override the whole scale in a dark-mode selector.

No. The scale is calculated in your browser as you move the sliders, and nothing you enter is uploaded.

Build your shadow scale

Pick a preset, tune the curves, and copy the code. It takes a few minutes.