Neumorphism in CSS: Shadows Guide

May 28, 20266 min read

What Is Neumorphism?

Neumorphism (soft UI) is a design style that makes elements appear to extrude from or press into their background. The effect is achieved with two opposing box-shadows — one light and one dark — on an element whose background matches the surface beneath it.

The result looks like raised or sunken plastic: soft, tactile, and distinctly different from flat design or traditional material elevation. Popularized around 2020, neumorphism has found a niche in dashboard UIs, music players, and calculator interfaces.

How the Dual Shadow Works

Neumorphism relies on three things being the same color:

  1. The page background
  2. The element's background
  3. The midpoint between the two shadow colors
.neumorphic-raised {
  background: #e0e0e0;
  border-radius: 16px;
  box-shadow:
    8px 8px 16px #bebebe,    /* dark shadow (bottom-right) */
    -8px -8px 16px #ffffff;  /* light shadow (top-left) */
}

The dark shadow simulates the area where light is blocked. The light shadow simulates the area where light reflects off the raised surface. Together, they create the illusion of depth.

Inset (Pressed) Variant

Flip the shadows inward for a pushed-in effect:

.neumorphic-pressed {
  background: #e0e0e0;
  border-radius: 16px;
  box-shadow:
    inset 8px 8px 16px #bebebe,
    inset -8px -8px 16px #ffffff;
}

Generating Neumorphic Shadows

The shadow colors are derived from the background. For a background of #e0e0e0 (HSL: 0, 0%, 88%):

Shadow TypeCalculationResult
DarkDecrease lightness by ~10%#bebebe (HSL: 0, 0%, 75%)
LightIncrease lightness by ~10% or use white#ffffff

The offset and blur values control the depth perception:

DepthOffsetBlurEffect
Subtle4px8pxSlight raise, clean look
Medium8px16pxStandard neumorphic raised
Deep12px24pxStrong extrusion
Extra deep16px32pxDramatic, almost 3D

Practical Components

Neumorphic Button

.neu-button {
  background: #e0e0e0;
  border: none;
  border-radius: 12px;
  padding: 12px 28px;
  font-size: 1rem;
  cursor: pointer;
  box-shadow:
    6px 6px 12px #bebebe,
    -6px -6px 12px #ffffff;
  transition: box-shadow 0.15s ease;
}

.neu-button:active {
  box-shadow:
    inset 4px 4px 8px #bebebe,
    inset -4px -4px 8px #ffffff;
}

Neumorphic Input Field

.neu-input {
  background: #e0e0e0;
  border: none;
  border-radius: 12px;
  padding: 12px 16px;
  font-size: 1rem;
  box-shadow:
    inset 4px 4px 8px #bebebe,
    inset -4px -4px 8px #ffffff;
}

.neu-input:focus {
  outline: none;
  box-shadow:
    inset 4px 4px 8px #bebebe,
    inset -4px -4px 8px #ffffff,
    0 0 0 2px rgba(100, 100, 255, 0.3);
}

Neumorphic Toggle

.neu-toggle {
  width: 60px;
  height: 30px;
  background: #e0e0e0;
  border-radius: 15px;
  box-shadow:
    inset 4px 4px 8px #bebebe,
    inset -4px -4px 8px #ffffff;
  position: relative;
  cursor: pointer;
}

.neu-toggle::after {
  content: '';
  position: absolute;
  width: 24px;
  height: 24px;
  top: 3px;
  left: 3px;
  background: #e0e0e0;
  border-radius: 50%;
  box-shadow:
    3px 3px 6px #bebebe,
    -3px -3px 6px #ffffff;
  transition: transform 0.2s ease;
}

.neu-toggle.active::after {
  transform: translateX(30px);
  background: #a78bfa;
}

Limitations and Accessibility

Neumorphism has well-documented accessibility challenges:

Contrast Problems

Because the element's background matches the surface, text on neumorphic elements often has poor contrast. The shadows themselves are low-contrast by design.

IssueImpactMitigation
Low text contrastFails WCAG AA on many backgroundsUse dark text, ensure 4.5:1 ratio
Shadow visibilityShadows invisible to some usersNever rely on shadows alone for affordance
Toggle statesHard to distinguish pressed/raisedAdd color change or icon shift
Color blindnessDepth illusion collapsesUse labels and borders as backup

Design Guidelines for Accessible Neumorphism

  1. Always meet 4.5:1 text contrast — even if it means using a darker text color than the aesthetic strictly wants
  2. Add visible borders — a subtle 1px solid rgba(0,0,0,0.05) helps define boundaries
  3. Use color for state — don't rely solely on shadow direction (raised vs pressed) to show toggles
  4. Test with high contrast mode — neumorphic elements should degrade gracefully when shadows are removed

Tailwind Implementation

/* Add to tailwind.config.ts theme.extend.boxShadow */
'neu-raised': '8px 8px 16px rgba(190,190,190,0.8), -8px -8px 16px rgba(255,255,255,0.9)',
'neu-pressed': 'inset 8px 8px 16px rgba(190,190,190,0.8), inset -8px -8px 16px rgba(255,255,255,0.9)',
<button class="bg-[#e0e0e0] shadow-neu-raised rounded-xl px-6 py-3 active:shadow-neu-pressed">
  Click Me
</button>

When to Use Neumorphism

Neumorphism works best in:

  • Low-information-density UIs (dashboards, music players, calculators)
  • Settings pages with toggles and sliders
  • Visual showcase or portfolio sites

Avoid it for:

  • High-density data tables or text-heavy pages
  • Forms requiring clear error states
  • Apps where accessibility is a hard requirement (government, healthcare)

Try It Yourself

Build neumorphic shadows interactively — tweak both light and dark shadows, adjust offset and blur, and preview raised vs pressed states in real time.

👉 Box Shadow Generator