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
longpreset 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 alreadyrgba, 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.