What this tool does

The Box Shadow Builder is a visual editor for CSS box-shadow values, including the stacked multi-layer shadows that make modern card UIs look believable. Each layer has its own X / Y offset, blur, spread, color, opacity, and inset toggle, and the tool emits a clean CSS string, a Tailwind arbitrary-value class, or a SwiftUI .shadow() chain.

The live preview renders your shadow on a 280×200 card against three backgrounds (paper, surface, dark) so you can check it against light, neutral, and dark contexts at the same time.

Why multi-layer shadows

A single box-shadow always looks computery, light falls off in one fixed pattern. Real-world shadows have a hard close shadow plus a soft long shadow plus an ambient bounce. Stacking two or three layers gives you that depth without writing a render budget for it.

The classic recipe:

1. Tight + dark, 0 1px 2px rgba(0,0,0,0.06), the contact shadow against the surface. 2. Loose + soft, 0 8px 24px rgba(0,0,0,0.10), the ambient bounce above.

Add a third inset layer for inner depth, or a bright glow layer for focus states. The tool ships eight presets (sm, md, lg, xl, inner, card, glow, long) that demonstrate the full range.

Per-layer controls

  • X / Y, horizontal and vertical offset in pixels. Negative values shift the shadow up/left.
  • Blur, Gaussian blur radius. Larger blur = softer edge.
  • Spread, grows or shrinks the shadow before blur is applied. Negative spread on a soft shadow tightens it inward; positive spread gives a halo effect.
  • Color, pick from eight swatches (black, ink, brand, green, ochre, red, purple, teal) or paste a hex.
  • Opacity %, separate from the color so you can keep your hex pure and dial intensity.
  • Inset, flips the shadow to draw inside the box. Useful for pressed states and inner depth.
  • On/off toggle, turn a layer off without losing its values; flip back to compare.

Use the up/down arrows to reorder layers. Order matters when layers overlap: later layers paint on top.

Output formats

CSS, the canonical multiline format ready to paste into a stylesheet:

box-shadow:
  0 1px 2px rgba(0, 0, 0, 0.06),
  0 8px 24px rgba(0, 0, 0, 0.10);

Tailwind, an arbitrary-value class with underscores replacing spaces (Tailwind's escape syntax for box-shadow):

shadow-[0px_1px_2px_rgba(0,0,0,0.06),0px_8px_24px_rgba(0,0,0,0.10)]

SwiftUI, a chain of .shadow() modifiers, one per layer (inset shadows are dropped because SwiftUI doesn't render them natively):

.shadow(color: Color(red: 0.000, green: 0.000, blue: 0.000, opacity: 0.06), radius: 1, x: 0, y: 1)
.shadow(color: Color(red: 0.000, green: 0.000, blue: 0.000, opacity: 0.10), radius: 12, x: 0, y: 8)

Common gotchas

  • Spread on Tailwind defaults. Tailwind's named shadow classes (shadow-md, shadow-lg) include subtle spread tweaks that arbitrary-value strings don't reproduce by default. If you copy a preset and find it slightly different from the Tailwind preset of the same name, that's why.
  • Inset shadows don't show in SwiftUI. The SwiftUI emitter skips inset layers and prints a comment. Apple's .shadow() only does outer drop shadows; inset effects need a custom shape mask.
  • Long-shadow performance. The built-in long preset stacks six layers. That's fine for one element but expensive if you stamp it across hundreds of cards. Profile before shipping.
  • Color + opacity vs rgba. The tool stores hex + opacity separately and emits rgba() at copy time. If you paste in a value that's already rgba, the parser only knows hex, use the swatch + opacity instead.

Privacy

Shadow values, layers, and the generated code strings exist only in your browser. Nothing is uploaded; there's no autosave to a server. Close the tab and the work is local to that session.

Frequently asked

Does this tool save my work to a server?

No. Layers, presets, and the rendered preview live entirely in your browser tab. There's no autosave, no account, no upload. Closing the tab clears the state.

Why use multiple layers instead of one big shadow?

Real shadows are not a single Gaussian. A tight contact shadow plus a soft ambient shadow gives the illusion of depth that one layer can't match. The named CSS shadow systems (Tailwind, Material) all stack two layers for the same reason.

What's the difference between blur and spread?

Spread grows or shrinks the solid shape of the shadow before blur is applied. Blur softens the edge after that. Negative spread + large blur = a tight, glowing halo. Positive spread + zero blur = a hard rectangular shadow.

Why does the SwiftUI output skip my inset layer?

SwiftUI's .shadow() modifier only renders outer drop shadows. Inset effects need a custom shape mask or a clipped overlay, which doesn't fit a single .shadow() call. The emitter prints a comment when it has to drop layers.

Can I copy the result as a CSS variable?

Not directly — the copy formats are plain CSS, Tailwind, or SwiftUI. To make it a variable, paste into your stylesheet and wrap it: --shadow-card: <pasted value>;. The tool keeps the indentation friendly for that.

What's the difference between the 'card' and 'lg' presets?

Both stack two layers. 'card' is tuned for clickable surfaces — slightly tighter spread, more subtle ambient — and 'lg' is the bigger-step Tailwind preset. Try both and see which one feels right against your actual background.

Why is my shadow getting cut off in the preview?

The preview card is fixed at 280×200 with overflow visible, but very large blur or spread values can push the shadow past the visible viewport edge. The exported CSS is unaffected; it's just a preview-pane crop.

How does opacity differ from the alpha channel in hex?

The tool stores color as a 6-digit hex plus a separate 0–100 opacity. At copy time it produces rgba(r, g, b, alpha). 8-digit hex (e.g. #00000020) is equivalent but less readable in code review, which is why this tool emits rgba().