Skip to content

Shadows

Shadows

Shadows create depth and hierarchy in the interface. WEC Design System uses subtle, realistic shadows that enhance UI elements without overwhelming the content.

TokenValueUsage
--shadow-nonenoneNo shadow (default)
--shadow-sm0 1px 2px rgba(0, 0, 0, 0.05)Subtle hover, raised elements
--shadow-card0 2px 2px 0 rgba(158, 158, 158, 0.2)Package cards, content cards
--shadow-md0 4px 4px rgba(158, 158, 158, 0.25)Buttons hover, navigation
--shadow-lg0 10px 15px -3px rgba(0, 0, 0, 0.1)Dropdowns, popovers
--shadow-xl0 20px 25px -5px rgba(0, 0, 0, 0.1)Modals, dialogs

Package cards and content cards use a subtle shadow:

.package-card {
box-shadow: 0 2px 2px 0 rgba(158, 158, 158, 0.2);
}
.package-card:hover {
box-shadow: 0 4px 8px rgba(158, 158, 158, 0.3);
}

Button hover states use a lifted shadow:

.button {
box-shadow: none;
transition: box-shadow 0.2s ease;
}
.button:hover {
box-shadow: 0 4px 4px rgba(158, 158, 158, 0.25);
}
.button:active {
box-shadow: 0 1px 2px rgba(158, 158, 158, 0.2);
}
.nav-arrow {
box-shadow: 0 4px 4px rgba(158, 158, 158, 0.25);
}
.nav-arrow:hover {
box-shadow: 0 6px 8px rgba(158, 158, 158, 0.3);
}
.modal-overlay {
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1),
0 10px 10px -5px rgba(0, 0, 0, 0.04);
}
.modal-content {
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
}
.dropdown {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1),
0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
.popover {
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
.custom-scrollbar::-webkit-scrollbar-thumb {
box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
}

Used for special effects on package cards:

.corner-accent {
box-shadow: -16px -16px #ff0025; /* Special red corner effect */
}

Animate shadows for smooth transitions:

.card {
box-shadow: 0 2px 2px 0 rgba(158, 158, 158, 0.2);
transition: box-shadow 0.2s ease;
}
.card:hover {
box-shadow: 0 4px 8px rgba(158, 158, 158, 0.3);
}

Shadows communicate elevation and hierarchy:

LevelShadowUsage
0 - FlatnoneBase surfaces, backgrounds
1 - Raised0 1px 2px rgba(0,0,0,0.05)Subtle hover, inline cards
2 - Card0 2px 2px rgba(158,158,158,0.2)Content cards, package cards
3 - Hover0 4px 4px rgba(158,158,158,0.25)Button hover, navigation
4 - Overlay0 10px 15px rgba(0,0,0,0.1)Dropdowns, tooltips
5 - Modal0 20px 25px rgba(0,0,0,0.1)Dialogs, modals

Combine shadows for depth:

/* Subtle multi-layer */
.subtle-depth {
box-shadow:
0 1px 1px rgba(0, 0, 0, 0.08),
0 2px 2px rgba(0, 0, 0, 0.04);
}
/* Medium depth */
.medium-depth {
box-shadow:
0 2px 4px rgba(0, 0, 0, 0.1),
0 8px 16px rgba(0, 0, 0, 0.05);
}
/* High depth */
.high-depth {
box-shadow:
0 4px 8px rgba(0, 0, 0, 0.1),
0 16px 32px rgba(0, 0, 0, 0.05);
}

Use brand colors for special emphasis:

/* Red glow for primary actions */
.button-primary:hover {
box-shadow: 0 4px 12px rgba(255, 0, 37, 0.3);
}
/* Blue glow for info states */
.info-card {
box-shadow: 0 4px 12px rgba(0, 80, 174, 0.2);
}
/* Green glow for success */
.success-badge {
box-shadow: 0 2px 8px rgba(0, 142, 83, 0.3);
}

Shadows in dark mode use lighter values:

/* Light mode */
.card {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
/* Dark mode */
[data-theme="dark"] .card {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.4);
}

Shadows work best with appropriate border radius:

/* Sharp corners - minimal shadow */
.sharp-card {
border-radius: 0;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}
/* Medium radius - standard shadow */
.rounded-card {
border-radius: 8px;
box-shadow: 0 2px 2px rgba(158, 158, 158, 0.2);
}
/* Large radius - softer shadow */
.pill-card {
border-radius: 20px;
box-shadow: 0 4px 8px rgba(158, 158, 158, 0.2);
}
:root {
/* Shadow Scale */
--shadow-none: none;
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-card: 0 2px 2px 0 rgba(158, 158, 158, 0.2);
--shadow-md: 0 4px 4px rgba(158, 158, 158, 0.25);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
/* Special Shadows */
--shadow-inset: inset 0 0 6px rgba(0, 0, 0, 0.3);
--shadow-corner-accent: -16px -16px #ff0025;
/* Multi-Layer Shadows */
--shadow-subtle:
0 1px 1px rgba(0, 0, 0, 0.08),
0 2px 2px rgba(0, 0, 0, 0.04);
--shadow-medium:
0 2px 4px rgba(0, 0, 0, 0.1),
0 8px 16px rgba(0, 0, 0, 0.05);
--shadow-high:
0 4px 8px rgba(0, 0, 0, 0.1),
0 16px 32px rgba(0, 0, 0, 0.05);
/* Colored Shadows */
--shadow-primary: 0 4px 12px rgba(255, 0, 37, 0.3);
--shadow-info: 0 4px 12px rgba(0, 80, 174, 0.2);
--shadow-success: 0 2px 8px rgba(0, 142, 83, 0.3);
--shadow-warning: 0 2px 8px rgba(253, 162, 43, 0.3);
--shadow-error: 0 2px 8px rgba(188, 29, 66, 0.3);
}
<div className="rounded-lg shadow-card hover:shadow-md transition-shadow">
<h3>Combo Internet 50GB</h3>
<p>Rp 50.000</p>
</div>
.button {
background: linear-gradient(76.81deg, #B90024, #FF0025, #FD195E);
box-shadow: none;
}
.button:hover {
box-shadow: 0 4px 12px rgba(255, 0, 37, 0.3);
transform: translateY(-2px);
}
.button:active {
box-shadow: 0 1px 2px rgba(255, 0, 37, 0.2);
transform: translateY(0);
}
.modal-backdrop {
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(4px);
}
.modal-content {
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
border-radius: 20px;
}
✅ Do❌ Don’t
Use subtle shadows for cardsUse heavy, dark shadows
Animate shadow changesJump between shadow levels
Match shadow to elevationUse random shadow values
Consider dark modeUse same shadow in all themes
Use colored shadows for emphasisOveruse colored shadows
@media (prefers-reduced-motion: reduce) {
* {
transition: none !important;
}
}

Don’t replace focus indicators with shadows:

/* Bad - shadow alone isn't visible enough */
.button:focus {
box-shadow: 0 0 0 4px rgba(255, 0, 37, 0.3);
}
/* Good - combine with outline */
.button:focus-visible {
outline: 2px solid #0050AE;
outline-offset: 2px;
box-shadow: 0 4px 12px rgba(255, 0, 37, 0.3);
}

Use transform instead of animating box-shadow:

/* Less performant - animates shadow */
.card:hover {
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
}
/* More performant - uses transform */
.card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
}
.card {
will-change: transform, box-shadow;
}
.card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.2);
}
.card.is-hovered {
will-change: auto; /* Reset after animation */
}

When applying shadows:

  • Is the shadow subtle and realistic?
  • Does the shadow match the element’s elevation?
  • Is there proper contrast with the background?
  • Does the shadow animate smoothly?
  • Does it work in both light and dark modes?
  • Is the shadow accessible (doesn’t replace focus indicators)?
  • Is the animation performant (GPU-accelerated)?