What is Neumorphism?
Neumorphism (a portmanteau of "new" and "skeuomorphism") is a UI design trend that emerged around 2019–2020, pioneered by designer Alexander Plyuto. Unlike flat design — which uses no shadows — or skeuomorphism — which mimics physical materials with textures — neumorphism finds a middle ground: elements appear to be physically extruded from the surface they sit on.
The illusion is created entirely with CSS box-shadow. The key insight is that a surface lit from the top-left casts a light reflection on the top-left edges and a shadow on the bottom-right edges. By applying both a lighter-than-background and a darker-than-background shadow on the same element — with the same background color as the page — the element appears to pop out from or sink into the surface.
This makes neumorphism entirely possible in pure CSS. No images, no textures, no JavaScript. Just background color knowledge and two shadow values. It has remained a popular aesthetic for dashboards, control panels, music players, and iOS-style app UIs throughout 2025 and 2026.
The element's background color must exactly match the page background. If they differ, the illusion breaks. Everything flows from this constraint.
The CSS Shadow Formula
The formula for a raised neumorphic element uses two shadows:
- Light shadow — top-left offset, lighter than background, simulates light source
- Dark shadow — bottom-right offset, darker than background, simulates cast shadow
For a light background of #e0e5ec (a warm, slightly blue-grey — the classic neumorphism base), the formula looks like this:
/* Classic light neumorphism — base color #e0e5ec */
.neu-raised {
background: #e0e5ec;
border-radius: 16px;
box-shadow:
-6px -6px 14px rgba(255, 255, 255, 0.85), /* light: top-left */
6px 6px 14px rgba(163, 177, 198, 0.60); /* dark: bottom-right */
}
The offset values (-6px / 6px here) control how pronounced the extrusion appears. The blur value (14px) controls how soft the edges are. Larger offsets and blur = more dramatic depth. Smaller values = subtle, almost flat appearance. A good starting range is 4–10px offset and 8–20px blur.
Choosing your shadow colors
The shadow colors are always derived from your base background. The light shadow is typically rgba(255,255,255,0.7–0.9) for light backgrounds. The dark shadow is the background color shifted darker — for #e0e5ec the dark shadow is approximately rgba(163,177,198,0.5–0.7). You can also use hex with opacity:
/* Alternative: use hex colors directly */
.neu-raised {
background: #e0e5ec;
box-shadow:
-6px -6px 14px #ffffff, /* pure white highlight */
6px 6px 14px #a3b1c6; /* darkened variant of #e0e5ec */
}
Use our CSS Box Shadow Generator to experiment with offset, blur, and color values and see the result live before copying the code.
The Three States: Flat, Pressed, Floating
Neumorphism has three standard UI states, each communicating a different interaction status. Understanding all three is essential for building complete interactive components.
State 1: Flat (default)
The default raised state — element appears to protrude from the surface. Use this for resting UI elements: cards, containers, and buttons in their default state.
.neu-flat {
background: #e0e5ec;
border-radius: 16px;
box-shadow:
-6px -6px 14px rgba(255, 255, 255, 0.85),
6px 6px 14px rgba(163, 177, 198, 0.60);
}
State 2: Pressed (inset)
The element appears sunken into the surface. Achieved by switching to inset shadows — the same colors and values but applied inside the element boundary. Use for active/clicked states, toggle-on states, and selected inputs.
.neu-pressed {
background: #e0e5ec;
border-radius: 16px;
box-shadow:
inset 4px 4px 10px rgba(163, 177, 198, 0.60),
inset -4px -4px 10px rgba(255, 255, 255, 0.85);
}
/* Note: inset reverses which shadow is light/dark */
/* Light shadow now bottom-right, dark shadow now top-left */
State 3: Floating (hover/focus)
A more exaggerated version of the flat state — larger offsets and higher opacity — making the element appear to lift higher off the surface. Use for hover and focus states to give clear interactive feedback.
.neu-floating {
background: #e0e5ec;
border-radius: 16px;
box-shadow:
-10px -10px 20px rgba(255, 255, 255, 0.90),
10px 10px 20px rgba(163, 177, 198, 0.70);
}
Dark Mode Neumorphism
Dark neumorphism uses the same principle but requires careful shadow calibration because you have much less room to work with. On a dark background, the light shadow becomes a very subtle highlight and the dark shadow must be near-black.
/* Dark neumorphism — base color #1e1e2a */
.neu-dark-raised {
background: #1e1e2a;
border-radius: 16px;
box-shadow:
-5px -5px 12px rgba(255, 255, 255, 0.04), /* very subtle highlight */
5px 5px 12px rgba(0, 0, 0, 0.50); /* strong dark shadow */
}
.neu-dark-pressed {
background: #1e1e2a;
border-radius: 16px;
box-shadow:
inset 4px 4px 10px rgba(0, 0, 0, 0.50),
inset -4px -4px 10px rgba(255, 255, 255, 0.04);
}
The light highlight in dark neumorphism must be very subtle — rgba(255,255,255,0.03–0.06). If it's too bright it looks artificial. The dark shadow should be strong (opacity 0.4–0.6) to create believable depth.
Real Components: Buttons, Cards, Inputs, Toggles
Here are complete, production-ready implementations of the most common neumorphic UI components.
Neumorphic Button
.neu-btn {
background: #e0e5ec;
color: #6b7a9a;
font-weight: 700;
font-size: 0.9rem;
padding: 14px 32px;
border: none;
border-radius: 12px;
cursor: pointer;
box-shadow:
-5px -5px 12px rgba(255, 255, 255, 0.85),
5px 5px 12px rgba(163, 177, 198, 0.60);
transition: box-shadow 0.15s ease, color 0.15s ease;
}
.neu-btn:hover {
box-shadow:
-8px -8px 18px rgba(255, 255, 255, 0.90),
8px 8px 18px rgba(163, 177, 198, 0.70);
color: #5a6b9a;
}
.neu-btn:active {
box-shadow:
inset 4px 4px 10px rgba(163, 177, 198, 0.60),
inset -4px -4px 10px rgba(255, 255, 255, 0.85);
color: #7c6fff;
}
.neu-btn:focus-visible {
outline: 2px solid #7c6fff;
outline-offset: 3px;
}
Neumorphic Card
<div class="neu-card">
<h3>Card Title</h3>
<p>Card content goes here.</p>
</div>
.neu-card {
background: #e0e5ec;
border-radius: 20px;
padding: 28px 32px;
box-shadow:
-8px -8px 18px rgba(255, 255, 255, 0.85),
8px 8px 18px rgba(163, 177, 198, 0.60);
}
.neu-card h3 {
font-size: 1.1rem;
font-weight: 700;
color: #4a5568;
margin-bottom: 10px;
}
.neu-card p {
font-size: 0.88rem;
color: #6b7a9a;
line-height: 1.7;
}
Neumorphic Input Field
.neu-input {
background: #e0e5ec;
border: none;
border-radius: 10px;
padding: 14px 18px;
font-size: 0.9rem;
color: #4a5568;
width: 100%;
/* Inputs are always pressed/inset by default */
box-shadow:
inset 3px 3px 8px rgba(163, 177, 198, 0.55),
inset -3px -3px 8px rgba(255, 255, 255, 0.80);
outline: none;
transition: box-shadow 0.15s ease;
}
.neu-input::placeholder {
color: #a3b1c6;
}
.neu-input:focus {
box-shadow:
inset 4px 4px 10px rgba(163, 177, 198, 0.60),
inset -4px -4px 10px rgba(255, 255, 255, 0.85),
0 0 0 2px rgba(124, 111, 255, 0.4); /* visible focus ring */
}
Neumorphic Toggle Switch
<label class="neu-toggle">
<input type="checkbox" hidden>
<span class="neu-toggle-track">
<span class="neu-toggle-thumb"></span>
</span>
</label>
.neu-toggle-track {
display: block;
width: 60px; height: 30px;
border-radius: 15px;
background: #e0e5ec;
box-shadow:
inset 3px 3px 7px rgba(163, 177, 198, 0.55),
inset -3px -3px 7px rgba(255, 255, 255, 0.80);
position: relative;
cursor: pointer;
transition: box-shadow 0.2s;
}
.neu-toggle-thumb {
position: absolute;
top: 4px; left: 4px;
width: 22px; height: 22px;
border-radius: 50%;
background: #e0e5ec;
box-shadow:
-3px -3px 7px rgba(255, 255, 255, 0.85),
3px 3px 7px rgba(163, 177, 198, 0.60);
transition: transform 0.2s ease;
}
input:checked + .neu-toggle-track { box-shadow: inset 3px 3px 7px rgba(100, 80, 220, 0.3), inset -3px -3px 7px rgba(160, 140, 255, 0.15); }
input:checked + .neu-toggle-track .neu-toggle-thumb { transform: translateX(30px); background: #7c6fff; box-shadow: -2px -2px 5px rgba(120,100,255,0.5), 2px 2px 5px rgba(40,20,180,0.4); }
Theming with CSS Custom Properties
The cleanest way to implement neumorphism is with CSS custom properties. This lets you switch the entire theme — light mode, dark mode, or any color accent — by changing a handful of variables.
/* Light neumorphism theme */
:root {
--neu-bg: #e0e5ec;
--neu-light: rgba(255, 255, 255, 0.85);
--neu-dark: rgba(163, 177, 198, 0.60);
--neu-offset: 6px;
--neu-blur: 14px;
--neu-text: #4a5568;
--neu-accent: #7c6fff;
}
/* Dark neumorphism theme */
[data-theme="dark"] {
--neu-bg: #1e1e2a;
--neu-light: rgba(255, 255, 255, 0.04);
--neu-dark: rgba(0, 0, 0, 0.50);
--neu-offset: 5px;
--neu-blur: 12px;
--neu-text: #a0aec0;
--neu-accent: #7c6fff;
}
/* Now all components use variables */
.neu-raised {
background: var(--neu-bg);
box-shadow:
calc(-1 * var(--neu-offset)) calc(-1 * var(--neu-offset)) var(--neu-blur) var(--neu-light),
var(--neu-offset) var(--neu-offset) var(--neu-blur) var(--neu-dark);
}
.neu-pressed {
background: var(--neu-bg);
box-shadow:
inset var(--neu-offset) var(--neu-offset) var(--neu-blur) var(--neu-dark),
inset calc(-1 * var(--neu-offset)) calc(-1 * var(--neu-offset)) var(--neu-blur) var(--neu-light);
}
Animating Between States
The most satisfying interaction in neumorphism is the flat-to-pressed transition on button click. CSS transition on box-shadow handles this beautifully — a 150ms ease feels natural and immediate, while 200–250ms feels more deliberate.
/* Smooth flat → pressed animation */
.neu-btn {
background: var(--neu-bg);
border-radius: 12px;
border: none;
padding: 14px 28px;
cursor: pointer;
box-shadow:
-6px -6px 14px var(--neu-light),
6px 6px 14px var(--neu-dark);
transition:
box-shadow 0.15s ease,
transform 0.1s ease;
}
.neu-btn:active {
box-shadow:
inset 4px 4px 10px var(--neu-dark),
inset -4px -4px 10px var(--neu-light);
transform: scale(0.98); /* slight physical "press" feel */
}
Pulsing neumorphic glow
For ambient, non-interactive elements like status indicators or loaders, you can animate the shadow intensity to create a breathing/pulsing effect:
@keyframes neu-pulse {
0%, 100% {
box-shadow:
-6px -6px 14px rgba(255,255,255,0.85),
6px 6px 14px rgba(163,177,198,0.60);
}
50% {
box-shadow:
-10px -10px 22px rgba(255,255,255,0.95),
10px 10px 22px rgba(163,177,198,0.75);
}
}
.neu-pulse {
background: #e0e5ec;
border-radius: 50%;
animation: neu-pulse 2.5s ease-in-out infinite;
}
/* Respect reduced motion preferences */
@media (prefers-reduced-motion: reduce) {
.neu-pulse { animation: none; }
}
Accessibility and Contrast
This is the most important section of this guide. Standard neumorphism frequently fails WCAG 2.1 accessibility requirements, and this is the main reason it fell out of favor for primary UI patterns. The problem is structural: when the element and surface share the same background color, there is zero contrast between the element boundary and the surface it sits on.
A user with low vision, cataracts, or a poorly calibrated display may not see neumorphic elements at all. WCAG 2.1 AA requires a minimum 3:1 contrast ratio for UI components against their surrounding — and most neumorphic implementations fail this.
How to fix it
There are several approaches to improve neumorphism's accessibility without abandoning the aesthetic:
/* A 1px border at low opacity adds definition without breaking the aesthetic */
.neu-accessible {
background: #e0e5ec;
border: 1px solid rgba(163, 177, 198, 0.35);
border-radius: 16px;
box-shadow:
-6px -6px 14px rgba(255,255,255,0.85),
6px 6px 14px rgba(163,177,198,0.60);
}
/* Add accent color on hover/focus to create clear interactive signal */
.neu-btn:hover,
.neu-btn:focus-visible {
box-shadow:
-8px -8px 18px rgba(255,255,255,0.90),
8px 8px 18px rgba(163,177,198,0.70),
0 0 0 2px #7c6fff; /* accent outline */
}
/* Always add a visible focus ring — never remove outline without replacement */
.neu-btn:focus-visible {
outline: 2px solid #7c6fff;
outline-offset: 4px;
}
Always test your neumorphic designs with a contrast checker. The WebAIM Contrast Checker is free and reliable. Use neumorphism for decorative cards and containers rather than primary interactive controls where possible. When used for buttons and inputs, always add a clear focus indicator.
Neumorphism vs Glassmorphism
Both are popular CSS-only design trends, but they achieve completely different effects and suit different contexts.
| Property | Neumorphism | Glassmorphism |
|---|---|---|
| Core technique | Two box-shadows (light + dark) | backdrop-filter: blur() + semi-transparent bg |
| Background requirement | Solid, monochromatic surface | Colorful, vibrant background image or gradient |
| Color palette | Monochromatic — all one hue | High contrast — vivid colors show through |
| Best for | Control panels, music players, dashboards | Landing pages, cards over gradients, modal overlays |
| Dark mode | Works but needs careful calibration | Works naturally — dark backgrounds look great |
| Accessibility | ⚠ Contrast issues without fixes | ⚠ Also has contrast issues at low opacity |
| Performance | ✓ No GPU cost — just shadows | ⚠ backdrop-filter is GPU-intensive |
You can also combine both: a glassmorphism card with neumorphic inner controls is a popular pattern for modern web apps. Try our Glassmorphism Generator if you want to explore the frosted glass aesthetic.
Build neumorphism shadows visually
Use the CSS Box Shadow Generator to experiment with offset, blur, color and layering. See the neumorphic effect live before copying your CSS.
Open Box Shadow Generator →Frequently Asked Questions
What is neumorphism in CSS?
Neumorphism (soft UI) is a design style that uses two box-shadow values on an element — one lighter and one darker than the background — to create the illusion that the element is physically extruded from or pressed into the surface. The element's background must match the page background exactly for the effect to work.
How do you create a neumorphism effect in CSS?
Apply two box-shadows of the same hue as your background: box-shadow: -6px -6px 14px rgba(255,255,255,0.85), 6px 6px 14px rgba(163,177,198,0.60);. The element's background property must match the page background exactly. Adjust offsets (4–10px) and blur (8–20px) to control depth.
Is neumorphism accessible?
Standard neumorphism fails WCAG contrast requirements because elements share the same background as the surface. Fix this by adding a subtle border (border: 1px solid rgba(163,177,198,0.35)), using accent colors on interactive states, and always providing a visible focus ring. Test with a contrast checker before shipping.
What is the difference between neumorphism and glassmorphism?
Neumorphism uses dual box-shadows to extrude elements from a solid monochromatic background. Glassmorphism uses backdrop-filter: blur() and a semi-transparent background to create a frosted glass look over a colorful backdrop. Neumorphism works on flat surfaces; glassmorphism needs a vivid background behind it.
Can I animate neumorphism?
Yes — transition: box-shadow 0.15s ease creates a smooth flat-to-pressed animation on buttons. You can also use @keyframes to animate shadow intensity for a pulsing/breathing effect on status indicators. Always include @media (prefers-reduced-motion: reduce) to disable animations for users who prefer it.
What background color should I use for neumorphism?
The classic neumorphism palette uses a slightly warm grey-blue: #e0e5ec is the most popular light base. Avoid pure white (#ffffff) — there's nowhere for the light shadow to go. For dark mode, #1e1e2a or #23232f work well. The exact hue matters less than having room to go both lighter and darker.
Does neumorphism work in all browsers?
Yes — box-shadow is universally supported across all modern browsers including Chrome, Firefox, Safari, and Edge. There are no compatibility concerns for neumorphism. It's one of the most browser-compatible design trends available.