Skip to content

Shadows

Shadow utilities add depth with box-shadow. Each size is a token, so every shadow-md on a page can be retuned in one place.

  • Sizes. sm, md, lg, xl, hero and monster name entries of $shadow-sizes. Each entry has an x offset, y offset, blur and spread.
  • Colours. default, dark, darker and darkest name entries of $shadow-colors, from 10% to 50% black.
  • Tokens. The default colour is emitted as --nu-shadow-{size}, and shadow-{size} outputs var(--nu-shadow-{size}). The darker colour classes and inset shadows output a plain box-shadow value.
Class Meaning Examples
shadow-{size} Outer shadow in the default colour shadow-sm, shadow-lg
shadow-{size}-{colour} Outer shadow in a darker colour shadow-md-dark, shadow-xl-darkest
shadow-inset-{size} Inner shadow shadow-inset-sm
shadow-inset-{size}-{colour} Inner shadow in a darker colour shadow-inset-md-darker
elevation-{level} Shadow plus a small z-index, levels 1 to 5 elevation-3
shadow-none Removes the shadow shadow-none

There is no bare shadow class; write a size.

Generated from the compiled core build.

KeyTokenValue
sm--nu-shadow-sm0 1px 2px 0 rgba(0, 0, 0, 0.1)
md--nu-shadow-md0 4px 6px -1px rgba(0, 0, 0, 0.1)
lg--nu-shadow-lg0 10px 15px -3px rgba(0, 0, 0, 0.1)
xl--nu-shadow-xl0 20px 25px -5px rgba(0, 0, 0, 0.1)
hero--nu-shadow-hero0 20px 25px 5px rgba(0, 0, 0, 0.1)
monster--nu-shadow-monster0 20px 55px 20px rgba(0, 0, 0, 0.1)
shadow-sm
shadow-md
shadow-lg
shadow-xl
<div class="flex wrap gap-8 p-4">
<div class="shadow-sm p-4 bg-surface rounded">shadow-sm</div>
<div class="shadow-md p-4 bg-surface rounded">shadow-md</div>
<div class="shadow-lg p-4 bg-surface rounded">shadow-lg</div>
<div class="shadow-xl p-4 bg-surface rounded">shadow-xl</div>
</div>

hero and monster have a positive spread and a large blur, for large floating panels. Give them room: the shadow extends well beyond the element.

shadow-hero
shadow-monster
<div class="flex wrap gap-16 p-12">
<div class="shadow-hero p-6 bg-surface rounded">shadow-hero</div>
<div class="shadow-monster p-6 bg-surface rounded">shadow-monster</div>
</div>

Add -dark, -darker or -darkest to a size for a stronger shadow. Use them on darker backgrounds, where the default 10% black is hard to see.

shadow-md
shadow-md-dark
shadow-md-darker
shadow-md-darkest
<div class="flex wrap gap-8 p-4 bg-alternate rounded">
<div class="shadow-md p-4 bg-surface rounded">shadow-md</div>
<div class="shadow-md-dark p-4 bg-surface rounded">shadow-md-dark</div>
<div class="shadow-md-darker p-4 bg-surface rounded">shadow-md-darker</div>
<div class="shadow-md-darkest p-4 bg-surface rounded">shadow-md-darkest</div>
</div>
shadow-inset-sm
shadow-inset-md-dark
<div class="flex wrap gap-4">
<div class="shadow-inset-sm p-4 bg-surface rounded">shadow-inset-sm</div>
<div class="shadow-inset-md-dark p-4 bg-surface rounded">shadow-inset-md-dark</div>
</div>

elevation-1 to elevation-5 pair a shadow with a z-index equal to the level, so a more raised sibling also stacks above a less raised one.

Class Shadow z-index
elevation-1 var(--nu-shadow-sm) 1
elevation-2 var(--nu-shadow-md) 2
elevation-3 var(--nu-shadow-lg) 3
elevation-4 var(--nu-shadow-xl) 4
elevation-5 var(--nu-shadow-monster) 5

The z-index is a small local scale for ordering raised siblings, not a page layer. For dropdowns, modals and other layers, add a level class such as z-dropdown; level classes come later in the stylesheet and override the elevation z-index. See Z-index. Elevation only stacks elements that are positioned (relative, absolute and so on) or are flex or grid items.

elevation-1
elevation-3
elevation-5
<div class="flex gap-8 p-4">
<div class="elevation-1 relative p-4 bg-surface rounded">elevation-1</div>
<div class="elevation-3 relative p-4 bg-surface rounded">elevation-3</div>
<div class="elevation-5 relative p-4 bg-surface rounded">elevation-5</div>
</div>

shadow-none sets box-shadow: none. It comes after the shadow and elevation classes, so it removes their shadow without !important. With elevation-* it removes the shadow and keeps the z-index.

Variant Classes
hover:, focus: Every size and colour: hover:shadow-lg, focus:shadow-md-dark
active: Every size and colour: active:shadow-sm

Inset shadows and shadow-none have no state variants.

Hover me
<div class="flex wrap gap-8 p-4">
<div class="shadow-sm hover:shadow-xl p-4 bg-surface rounded">Hover me</div>
<button class="shadow-md active:shadow-sm" type="button">Press me</button>
</div>

Outer shadow classes, their hover: and focus: forms and shadow-none have responsive variants with an @{breakpoint} suffix (shadow-lg@md, hover:shadow-xl@lg, shadow-none@md). Inset shadows, active: shadows and elevation classes have none.

shadow-none shadow-lg@md: resize the window
<div class="p-4">
<div class="shadow-none shadow-lg@md p-4 bg-surface rounded">shadow-none shadow-lg@md: resize the window</div>
</div>
SuffixMedia query
@xs@media (min-width: 480px)
@sm@media (min-width: 640px)
@md@media (min-width: 768px)
@lg@media (min-width: 1024px)
@xl@media (min-width: 1280px)
@2xl@media (min-width: 1536px)
@use "@nuvoui/core" as *;
.card {
@include apply(shadow(sm), shadow(lg) hover, shadow(md, dark) lg);
}
.card {
box-shadow: var(--nu-shadow-sm);
}
.card:hover {
box-shadow: var(--nu-shadow-lg);
}
@media (min-width: 1024px) {
.card {
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.2);
}
}
Mixin Arguments
shadow($size: md, $color: default) A size and a colour from the config maps; the default colour outputs the token
shadow-inset($size: md, $color: default) As shadow(), inset, always a plain value
elevation($level) 1 to 5
shadow-base($x, $y, $blur, $spread, $color) Any values, for a one-off shadow

shadow() accepts configured keys only. For a shadow outside the scale, use shadow-base() or write box-shadow yourself.

.floating-button {
@include shadow-base(0, 2px, 8px, 0, rgb(0 0 0 / 25%));
}
.popover {
box-shadow: token(shadow-lg);
}

$shadow-sizes maps each size to its x, y, blur and spread; $shadow-colors maps each colour name to a colour. Each replaces the default map; it is not merged. Keep the default colour, and keep sm, md, lg, xl and monster, which the elevation classes use.

@use "@nuvoui/core" with (
$generate-utility-classes: true,
$shadow-colors: ("default": rgb(15 23 42 / 12%), "dark": rgb(15 23 42 / 24%), "darker": rgb(15 23 42 / 36%), "darkest": rgb(15 23 42 / 50%))
);

Changing a colour changes every token and class that uses it: here the tokens become 0 1px 2px 0 rgba(15, 23, 42, 0.12) and so on.

Input Error
shadow(huge) Shadow size 'huge' not found in config-shadow.$shadow-sizes map
shadow(md, red) Shadow color 'red' not found in config-shadow.$shadow-colors map
elevation(6) elevation(6): use a level from 1 to 5.
Variable Description
--nu-shadow-{size} One token per key of $shadow-sizes, in the default colour. Fixed across themes. See Scale.

Generated from the compiled core build. Responsive and state variants are not listed.

Shadow (7 rules)
SelectorDeclarationsDefault value
.shadow-smbox-shadow: var(--nu-shadow-sm)0 1px 2px 0 rgba(0, 0, 0, 0.1)
.shadow-mdbox-shadow: var(--nu-shadow-md)0 4px 6px -1px rgba(0, 0, 0, 0.1)
.shadow-lgbox-shadow: var(--nu-shadow-lg)0 10px 15px -3px rgba(0, 0, 0, 0.1)
.shadow-xlbox-shadow: var(--nu-shadow-xl)0 20px 25px -5px rgba(0, 0, 0, 0.1)
.shadow-herobox-shadow: var(--nu-shadow-hero)0 20px 25px 5px rgba(0, 0, 0, 0.1)
.shadow-monsterbox-shadow: var(--nu-shadow-monster)0 20px 55px 20px rgba(0, 0, 0, 0.1)
.shadow-nonebox-shadow: nonenone
Shadow colours (18 rules)
SelectorDeclarationsDefault value
.shadow-sm-darkbox-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.2)0 1px 2px 0 rgba(0, 0, 0, 0.2)
.shadow-sm-darkerbox-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.35)0 1px 2px 0 rgba(0, 0, 0, 0.35)
.shadow-sm-darkestbox-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.5)0 1px 2px 0 rgba(0, 0, 0, 0.5)
.shadow-md-darkbox-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.2)0 4px 6px -1px rgba(0, 0, 0, 0.2)
.shadow-md-darkerbox-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.35)0 4px 6px -1px rgba(0, 0, 0, 0.35)
.shadow-md-darkestbox-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.5)0 4px 6px -1px rgba(0, 0, 0, 0.5)
.shadow-lg-darkbox-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.2)0 10px 15px -3px rgba(0, 0, 0, 0.2)
.shadow-lg-darkerbox-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.35)0 10px 15px -3px rgba(0, 0, 0, 0.35)
.shadow-lg-darkestbox-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.5)0 10px 15px -3px rgba(0, 0, 0, 0.5)
.shadow-xl-darkbox-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.2)0 20px 25px -5px rgba(0, 0, 0, 0.2)
.shadow-xl-darkerbox-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.35)0 20px 25px -5px rgba(0, 0, 0, 0.35)
.shadow-xl-darkestbox-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.5)0 20px 25px -5px rgba(0, 0, 0, 0.5)
.shadow-hero-darkbox-shadow: 0 20px 25px 5px rgba(0, 0, 0, 0.2)0 20px 25px 5px rgba(0, 0, 0, 0.2)
.shadow-hero-darkerbox-shadow: 0 20px 25px 5px rgba(0, 0, 0, 0.35)0 20px 25px 5px rgba(0, 0, 0, 0.35)
.shadow-hero-darkestbox-shadow: 0 20px 25px 5px rgba(0, 0, 0, 0.5)0 20px 25px 5px rgba(0, 0, 0, 0.5)
.shadow-monster-darkbox-shadow: 0 20px 55px 20px rgba(0, 0, 0, 0.2)0 20px 55px 20px rgba(0, 0, 0, 0.2)
.shadow-monster-darkerbox-shadow: 0 20px 55px 20px rgba(0, 0, 0, 0.35)0 20px 55px 20px rgba(0, 0, 0, 0.35)
.shadow-monster-darkestbox-shadow: 0 20px 55px 20px rgba(0, 0, 0, 0.5)0 20px 55px 20px rgba(0, 0, 0, 0.5)
Inset shadow (24 rules)
SelectorDeclarationsDefault value
.shadow-inset-smbox-shadow: inset 0 1px 2px 0 rgba(0, 0, 0, 0.1)inset 0 1px 2px 0 rgba(0, 0, 0, 0.1)
.shadow-inset-sm-darkbox-shadow: inset 0 1px 2px 0 rgba(0, 0, 0, 0.2)inset 0 1px 2px 0 rgba(0, 0, 0, 0.2)
.shadow-inset-sm-darkerbox-shadow: inset 0 1px 2px 0 rgba(0, 0, 0, 0.35)inset 0 1px 2px 0 rgba(0, 0, 0, 0.35)
.shadow-inset-sm-darkestbox-shadow: inset 0 1px 2px 0 rgba(0, 0, 0, 0.5)inset 0 1px 2px 0 rgba(0, 0, 0, 0.5)
.shadow-inset-mdbox-shadow: inset 0 4px 6px -1px rgba(0, 0, 0, 0.1)inset 0 4px 6px -1px rgba(0, 0, 0, 0.1)
.shadow-inset-md-darkbox-shadow: inset 0 4px 6px -1px rgba(0, 0, 0, 0.2)inset 0 4px 6px -1px rgba(0, 0, 0, 0.2)
.shadow-inset-md-darkerbox-shadow: inset 0 4px 6px -1px rgba(0, 0, 0, 0.35)inset 0 4px 6px -1px rgba(0, 0, 0, 0.35)
.shadow-inset-md-darkestbox-shadow: inset 0 4px 6px -1px rgba(0, 0, 0, 0.5)inset 0 4px 6px -1px rgba(0, 0, 0, 0.5)
.shadow-inset-lgbox-shadow: inset 0 10px 15px -3px rgba(0, 0, 0, 0.1)inset 0 10px 15px -3px rgba(0, 0, 0, 0.1)
.shadow-inset-lg-darkbox-shadow: inset 0 10px 15px -3px rgba(0, 0, 0, 0.2)inset 0 10px 15px -3px rgba(0, 0, 0, 0.2)
.shadow-inset-lg-darkerbox-shadow: inset 0 10px 15px -3px rgba(0, 0, 0, 0.35)inset 0 10px 15px -3px rgba(0, 0, 0, 0.35)
.shadow-inset-lg-darkestbox-shadow: inset 0 10px 15px -3px rgba(0, 0, 0, 0.5)inset 0 10px 15px -3px rgba(0, 0, 0, 0.5)
.shadow-inset-xlbox-shadow: inset 0 20px 25px -5px rgba(0, 0, 0, 0.1)inset 0 20px 25px -5px rgba(0, 0, 0, 0.1)
.shadow-inset-xl-darkbox-shadow: inset 0 20px 25px -5px rgba(0, 0, 0, 0.2)inset 0 20px 25px -5px rgba(0, 0, 0, 0.2)
.shadow-inset-xl-darkerbox-shadow: inset 0 20px 25px -5px rgba(0, 0, 0, 0.35)inset 0 20px 25px -5px rgba(0, 0, 0, 0.35)
.shadow-inset-xl-darkestbox-shadow: inset 0 20px 25px -5px rgba(0, 0, 0, 0.5)inset 0 20px 25px -5px rgba(0, 0, 0, 0.5)
.shadow-inset-herobox-shadow: inset 0 20px 25px 5px rgba(0, 0, 0, 0.1)inset 0 20px 25px 5px rgba(0, 0, 0, 0.1)
.shadow-inset-hero-darkbox-shadow: inset 0 20px 25px 5px rgba(0, 0, 0, 0.2)inset 0 20px 25px 5px rgba(0, 0, 0, 0.2)
.shadow-inset-hero-darkerbox-shadow: inset 0 20px 25px 5px rgba(0, 0, 0, 0.35)inset 0 20px 25px 5px rgba(0, 0, 0, 0.35)
.shadow-inset-hero-darkestbox-shadow: inset 0 20px 25px 5px rgba(0, 0, 0, 0.5)inset 0 20px 25px 5px rgba(0, 0, 0, 0.5)
.shadow-inset-monsterbox-shadow: inset 0 20px 55px 20px rgba(0, 0, 0, 0.1)inset 0 20px 55px 20px rgba(0, 0, 0, 0.1)
.shadow-inset-monster-darkbox-shadow: inset 0 20px 55px 20px rgba(0, 0, 0, 0.2)inset 0 20px 55px 20px rgba(0, 0, 0, 0.2)
.shadow-inset-monster-darkerbox-shadow: inset 0 20px 55px 20px rgba(0, 0, 0, 0.35)inset 0 20px 55px 20px rgba(0, 0, 0, 0.35)
.shadow-inset-monster-darkestbox-shadow: inset 0 20px 55px 20px rgba(0, 0, 0, 0.5)inset 0 20px 55px 20px rgba(0, 0, 0, 0.5)
Elevation (5 rules)
SelectorDeclarationsDefault value
.elevation-1box-shadow: var(--nu-shadow-sm)
z-index: 1
0 1px 2px 0 rgba(0, 0, 0, 0.1)
1
.elevation-2box-shadow: var(--nu-shadow-md)
z-index: 2
0 4px 6px -1px rgba(0, 0, 0, 0.1)
2
.elevation-3box-shadow: var(--nu-shadow-lg)
z-index: 3
0 10px 15px -3px rgba(0, 0, 0, 0.1)
3
.elevation-4box-shadow: var(--nu-shadow-xl)
z-index: 4
0 20px 25px -5px rgba(0, 0, 0, 0.1)
4
.elevation-5box-shadow: var(--nu-shadow-monster)
z-index: 5
0 20px 55px 20px rgba(0, 0, 0, 0.1)
5
  • Shadows are decoration. A shadow alone does not tell a screen reader or a high contrast user that something is raised or selected. Use a border, a heading or ARIA state for meaning.
  • Forced colours. Windows High Contrast mode removes box shadows. If a card’s edge matters, add a border (a border-transparent border becomes visible in forced colours).
  • Focus. focus:shadow-* is not a focus indicator on its own; keep the outline focus ring (WCAG 2.4.7 Focus Visible).
  • RTL. The default shadows have no horizontal offset, so they look the same in both directions. A custom shadow with an x offset does not mirror in right-to-left layouts.