Shadows
Soft shadows made from four stacked layers. Every shadow has the same layers, so you can animate from one to another.
Scale
--ui-shadow-1 is the smallest and
--ui-shadow-5 the largest.
--ui-shadow-0 is no shadow.
.card {
box-shadow: var(--ui-shadow-3);
}
Inset
--ui-shadow-inset-1 to --ui-shadow-inset-3
make a surface look pressed in, like a well.
--ui-shadow-inset-0 is no inset shadow.
.well {
box-shadow: var(--ui-shadow-inset-2);
}
Shiny
--ui-shadow-shiny-1 to --ui-shadow-shiny-3
make a surface look rounded and glossy, as if it catches the light.
Each one is a lit rim and an inner glow on top of the drop shadow of
the same level. --ui-shadow-shiny-0 is no shiny shadow.
The light shows best on a surface that is darker than white. Hover a
card to raise it one level.
.button {
box-shadow: var(--ui-shadow-shiny-1);
transition: box-shadow 400ms var(--ease-glide);
&:hover {
box-shadow: var(--ui-shadow-shiny-2);
}
}
The light is white by default and weaker in dark mode. Change it with
--ui-shadow-shine-color. It also has no value until you
set one, and works the same way as
--ui-shadow-color.
Classes
Every shadow also has a class with the same name, without the
--ui- prefix: .shadow-0 to
.shadow-5, .shadow-inset-0 to
.shadow-inset-3 and .shadow-shiny-0 to
.shadow-shiny-3. Use them when an element has no CSS of
its own. Set --ui-shadow-color on the element, or on a
parent, to color its shadow.
<article class="card shadow-3">...</article>
<div class="shadow-inset-2">...</div>
<button class="shadow-shiny-2">Generate</button>
<article
class="card shadow-3"
style="
--ui-shadow-color: color-mix(in oklch, var(--ui-primary) 40%, transparent);
"
>
...
</article>
Animate
Transition box-shadow between two tokens. To animate a
shadow in from nothing, start at --ui-shadow-0, not
none. Hover the card.
.card {
box-shadow: var(--ui-shadow-1);
transition: box-shadow 400ms var(--ease-glide);
&:hover {
box-shadow: var(--ui-shadow-4);
}
}
Stack
Add your own layers after the token, separated by a comma. To keep
the animation, give both states the same number of layers. Put
inset layers in the same place in both states.
.card {
box-shadow:
var(--ui-shadow-1),
0 0 0 1px var(--ui-neutral-200);
transition: box-shadow 400ms var(--ease-glide);
&:hover {
box-shadow:
var(--ui-shadow-4),
0 0 0 4px var(--ui-primary-200);
}
}
To animate between a raised and a pressed state, use both kinds in both states. Only the levels change, so each layer has a partner to animate to. Press the card.
.card {
box-shadow: var(--ui-shadow-1), var(--ui-shadow-inset-0);
transition: box-shadow 400ms var(--ease-glide);
&:hover {
box-shadow: var(--ui-shadow-3), var(--ui-shadow-inset-0);
}
&:active {
box-shadow: var(--ui-shadow-0), var(--ui-shadow-inset-1);
}
}
Color
All layers get their color from --ui-shadow-color. It
has no value until you set one, so the default is used. Set it on
:root to change every shadow on the page, also inside
[data-ui-theme] elements. Set it on a
[data-ui-theme] element to change the shadows of that
element and everything inside it. The
shadow classes also pick up a color set on
the element itself.
[data-ui-theme] {
--ui-shadow-color: color-mix(in oklch, var(--ui-primary) 40%, transparent);
box-shadow: var(--ui-shadow-3);
}