Inset box shadow: wells, pressed states and inner glow

The inset keyword, how inner shadows are drawn, and where they earn their place.

What the inset keyword does

Every other value in box-shadow is a number. inset is the one word, and it flips the whole effect inside out. MDN's description is the one I quote to clients when they ask why a button suddenly looks pushed in:

"Changes the shadow from an outer box-shadow to an inner box-shadow (as if the content is pressed into the box). Inset shadows are clipped to the element's padding box and appear above the background but below the content."

MDN Web Docs, box-shadow

Three facts in that one sentence decide how you use it. The shadow is drawn inside. It stops at the padding box, so it never spills into the border. And it sits above the background but below the content, which is why an inset shadow can darken a background image without dimming the text on top of it. The same offsets, blur and spread apply; they just describe an inner edge now, and a positive Y offset means the shadow hangs down from the top edge rather than falling below the bottom one.

How an inner shadow is drawn

The mental model that works: imagine the box is a hole cut in the page, and the page around it casts a shadow into the hole. An outer shadow is the box's silhouette blurred and painted outside; an inner shadow is the page's silhouette blurred and painted inside. The specification treats the box as opaque either way ("the shadow is drawn as if the box were solid"), so the shape of the inset shadow follows the padding box and its border radius exactly.

y 2, blur 6
y 8, blur 16
spread 2, no blur
The offset and blur set how deep the well reads. Spread alone, with no blur, is an inner border.

Because the shadow is clipped to the box, an inset shadow with a large offset does not leak anywhere; it simply darkens more of the interior from one edge. That makes it far more forgiving than an outer shadow, where a big offset floats the object off the page. Blur behaves as it does outside: the fade band straddles the edge, half of it invisible beyond the clip.

Wells and inputs

The most common honest use of inset is the well: a region that reads as sunk below the page. Search fields, text inputs, the track under a slider, the readout on this site. The recipe is a small top shadow plus a hairline ring, both inset, on a surface slightly darker than the page:

CSS
.well {
  background: #edeef3;
  box-shadow:
    inset 0 2px 6px rgba(27, 35, 64, 0.18),
    inset 0 0 0 1px rgba(27, 35, 64, 0.08);
}

The ring matters more than it looks. Without it the well's edge is only the fade of the shadow, and on a light surface that fade can drop below the 3:1 contrast a control boundary needs. With it, the edge is defined even where the shadow has faded to nothing. The slider tracks in the generator console are built exactly this way, and the inner shadow example opens this pair in the tool.

Pressed buttons

A button at rest has an outer shadow; a button being pressed has an inset one. Swapping between the two on :active is the oldest trick in interface CSS and it still works, because it matches what a physical key does. Keep the pressed shadow small and the offset positive, so the top edge darkens as though the button has gone down into the panel:

CSS
.btn {
  box-shadow: 0 1px 2px rgba(27, 35, 64, 0.12), 0 4px 12px rgba(27, 35, 64, 0.10);
}
.btn:active {
  box-shadow: inset 0 2px 4px rgba(27, 35, 64, 0.18);
  transform: translateY(1px);
}

Do not transition between the two; a shadow that morphs from outside to inside is a repaint on every frame and the result looks like a smear. Let it snap. The one pixel translate is what sells the press, and transform is free to animate.

The one pixel edge highlight

The most useful inset shadow on this site is not a shadow at all. It is a one pixel white line along the top edge of every raised surface: inset 0 1px 0 rgba(255, 255, 255, 0.9). It is the highlight a real object gets on the edge that faces the light, and it is the difference between a card that looks lit and one that looks pasted on. The console panel, every button and every card here carries it, always first in the list so it paints on top.

no edge
edge light
Same drop shadow. The right box adds the 1px inset highlight and a hairline ring, and reads as a lit object.

Inner glow on glass

Glassmorphism, the frosted card over a photograph, depends on inset shadows twice over. The card itself is a translucent box with backdrop-filter: blur(), which MDN defines as letting you "apply graphical effects such as blurring or color shifting to the area behind an element", with the caveat that "to see the effect the element or its background needs to be transparent or partially transparent". Once the box is translucent, an outer shadow alone is not enough to separate it from the photo; it needs a luminous edge, and that edge is an inset white shadow at low opacity, often with a little blur so it reads as light catching glass rather than a drawn line.

CSS
.glass {
  background: rgba(255, 255, 255, 0.35);
  backdrop-filter: blur(12px);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.6),
    0 8px 32px rgba(11, 21, 51, 0.24);
}

The glassmorphism example opens that on an image canvas so you can see the edge catch. Neumorphism uses the same pair in reverse, a light inset on one side and a dark inset on the other, to make a control look moulded into the surface; Adrian Bece's CSS-Tricks article notes that "a core part of neumorphic elements is the use of two shadows: a light shadow and a dark shadow", and then spends a section on why that is a contrast problem. The neumorphism example carries that caveat.

Inset shadows in the generator

  1. Select the layer you want inside the box and flip the Inset switch in the Shadow group. The handle on the stage gets a dashed ring to show the offset is now measured inward.
  2. Set the box colour a step darker than the canvas if you want a well. A white box on a white page shows an inset shadow but never reads as sunk.
  3. For an edge highlight, add a layer, set Y to 1, blur 0, colour white, opacity 90, and switch it to inset. Move it to the top of the layer list with the up arrow so it paints over the others.
  4. Check the CSS tab: the keyword is written first on each inset layer, which is where most people expect to find it.

Where inset looks wrong

Inset says "sunk" or "lit from within". Anything that is supposed to float above the page, a card, a menu, a modal, a tooltip, should not carry one as its main shadow, because the two messages cancel out and the element looks like a hole with a lid on it. The second failure is the inset shadow used as a border on a coloured button: at zero blur it is a border, and a border drawn inside the box eats into the padding and shifts the label. Use a real border or an outer spread-only shadow for that. And keep inset shadows off images: they paint above the background, so they darken the picture's edges in a way that looks like a dirty frame.

Frequently asked questions

What does inset do in CSS box-shadow?

It draws the shadow inside the element instead of outside it. The offsets, blur and spread mean the same things, but the shadow is clipped to the padding box and painted above the background, so it looks like the element is sunk into the page or lit from within.

How do I make an inset box shadow only on the top?

Give it a positive Y offset and a negative spread: inset 0 4px 6px -4px rgba(0,0,0,0.2). The negative spread pulls the shadow in from the sides so only the top edge shows. For only the bottom, use a negative Y.

Does inset box shadow cover the text?

No. Inset shadows are painted above the background but below the content, so text, icons and images inside the element stay on top of the shadow.

Can I use inset and outer shadows together?

Yes, in one comma separated list. Put the inset highlight first so it paints on top. This is how a raised card gets a bright top edge and a drop shadow from a single declaration.

Is inset box shadow good for form inputs?

Yes, it is the classic way to make an input read as a well. A small inset shadow at the top, plus a 1px inset ring for the border, gives the field depth without a heavy border. Keep the contrast of the ring at 3:1 against the page so the field boundary stays visible.

Why does my inset shadow look like a border?

Because the blur is zero or the spread is doing all the work. A spread-only inset shadow is a border drawn inside the box. Add blur and a Y offset to make it read as depth instead of a line.

Sources

  1. MDN Web Docs: box-shadow (inset)
  2. W3C, CSS Backgrounds and Borders Module Level 3, box-shadow
  3. MDN Web Docs: backdrop-filter
  4. Adrian Bece, Neumorphism and CSS, CSS-Tricks