Skip to content

Materials

Elevation, radius, and glass edge fades for depth and scroll chrome.

Use elevation for floating surfaces. Pair with shadow-hairline or a border for edges — lift and edge are separate tokens. Use glass fades when content scrolls under sticky chrome.

Preview

Name

Usage

Overview

Materials cover how surfaces lift, how corners round, and how scroll edges soften. Shadows use elevation levels 100400, exposed as shadow-sm through shadow-xl, plus a dedicated hairline edge. Radius runs from 2xs to 4xl. Glass pairs masked backdrop-blur-md with a surface tint gradient.

Shadow scale

Four elevation levels plus a hairline edge token.

ClassLevelUsage
shadow-hairlineedge1px theme-aware edge without a separate border.
shadow-sm100Subtle lift — chips, thumbs, tight cards.
shadow-md200Popovers, tooltips, small floating panels.
shadow-lg300Cards, menus, and elevated surfaces.
shadow-xl400Modals, dialogs, and high-focus overlays.

Component mapping

Pick elevation from the role of the surface, not from visual preference alone.

Component typeRecommended shadowRationale
Switch thumbs, chipsshadow-smBarely lifted control chrome.
Tooltips, small popoversshadow-mdClear separation from the trigger.
Cards, menus, selectsshadow-lgDefault elevated panel depth.
Modals and dialogsshadow-xlHighest practical elevation for focus.
Flat cards and tablesborder / shadow-hairlineSit in the layout rather than above it.

Shadow and hairline

Elevation and edge are separate tokens. Choose based on whether the surface floats or sits flat in the layout.

PatternWhen to use
shadow-sm … shadow-xlElevated surfaces — cards, menus, dialogs, floating panels.
shadow-hairlineTheme-aware 1px edge when you want a crisp outline without a border token.
border border-border-primaryNon-elevated dividers, sidebars, tables, and flat cards-by-design.

Prefer one clear edge treatment — hairline or border — unless the pattern needs both with shadow-lg.

Hover states

Increasing elevation on hover signals that a surface is interactive.

StateClassUsage
Defaultshadow-smResting interactive card.
Hoverhover:shadow-mdSubtle lift that reads as clickable.
Activeactive:shadow-smReturn to base elevation for press feedback.

tsx

<div className="shadow-sm hover:shadow-md active:shadow-sm transition-shadow">
  Card content
</div>

Radius

Prefer these corner radii over arbitrary rounded-[…] values.

Preview

Name

Usage

ClassValueUsage
rounded-2xs0.125rem (2px)Tight chips and dense UI.
rounded-xs0.25rem (4px)Badges and compact controls.
rounded-sm0.375rem (6px)Small controls and inputs.
rounded-md0.5rem (8px)Buttons, inputs, and checkboxes.
rounded-lg0.625rem (10px)Larger controls and tiles.
rounded-xl0.75rem (12px)Cards, menus, and popovers.
rounded-2xl1rem (16px)Elevated panels and sheets.
rounded-3xl1.25rem (20px)Feature cards and heroes.
rounded-4xl1.5rem (24px)Composer and large shells.
rounded-full9999px (full)Pills, avatars, and switches.

Nested radius

When a rounded child sits inside a padded, rounded parent, keep curves concentric: inner = outer − padding. Pick the nearest lower scale step when the result is not exact.

OuterPaddingInner
rounded-md (8)p-1 (4)rounded-xs (4)
rounded-lg (10)p-0.5 (2)rounded-md (8)
rounded-xl (12)p-1 (4)rounded-md (8)
rounded-xl (12)p-1.5 (6)rounded-sm (6)
rounded-xl (12)p-2 (8)rounded-xs (4)

tsx

{/* Select popup: rounded-md + p-1 → items use rounded-xs */}
<div className="rounded-md border p-1">
  <button type="button" className="rounded-xs px-2.5 py-1.5">
    Apple
  </button>
</div>

Glass

Soften content as it scrolls under sticky chrome. Stack a masked blur with a tint gradient — not a solid translucent bar. Prefer EdgeFade so top and bottom edges stay consistent.

  • Notes
  • References
  • Inspiration
  • Screenshots
  • Articles
  • Voice memos
  • PDFs
  • Bookmarks
  • Drafts
  • Archives

Scroll the list — masked backdrop-blur-md and tint share one fade so the edge reads as glass, not a milky wash.

Name

Recipe

Usage

LayerRecipeRole
Blurbackdrop-blur-md backdrop-saturate-150Frosted glass behind sticky edges and floating chrome.
Tint strongfrom-surface/80Start of an edge fade — keeps content readable.
Tint softvia-surface/40Mid stop before the edge becomes fully clear.
Edge topEdgeFade edge="top"Sticky headers and scroll tops (logo bars, page chrome).
Edge bottomEdgeFade edge="bottom"Scroll bottoms — keep last items clear with padding.

Composition

Two absolute layers behind the chrome. Blur and tint share one mask so they ease out together — separate fade curves read as a milky wash. Tint uses from-surface/80 via-surface/40 to-transparent (or background-primary on the page canvas). Avoid overflow: hidden on ancestors of the fade or backdrop-filter may not sample the scrolling content.

tsx

import { EdgeFade } from "@/components/edge-fade"

<div className="sticky top-0 z-10">
  <div className="pointer-events-none absolute inset-x-0 top-0 -z-10 h-[calc(100%+0.75rem)]">
    <EdgeFade edge="top" tone="surface" />
  </div>
  <div className="relative px-5 pt-5 pb-4">
    {/* sticky chrome */}
  </div>
</div>

{/* Bottom edge — pin to the scroll viewport */}
<div className="pointer-events-none absolute inset-x-0 bottom-0 z-10 h-12">
  <EdgeFade edge="bottom" tone="surface" />
</div>

Add bottom padding on the scroll content so the last items can clear the fade (about the same height as the bottom edge).

Usage guidelines

Do

  • Use shadow-smshadow-xl for elevated surfaces
  • Increase elevation on hover (shadow-smshadow-md) with transition-shadow
  • Use shadow-lg for cards and menus, shadow-xl for modals
  • Prefer radius tokens (rounded-md, rounded-xl) over custom radii
  • Nest radii with inner = outer − padding (e.g. select items inside a padded popup)
  • Use border or shadow-hairline for flat layout chrome
  • Use masked backdrop-blur-md plus a tint gradient for scroll edges — prefer EdgeFade

Don't

  • Don’t invent one-off multi-glow shadows outside the scale
  • Don’t jump from shadow-sm to shadow-xl on hover
  • Don’t apply elevation to inline text or icons alone
  • Don’t use rounded-[13px] when a scale step exists
  • Don’t reuse the parent radius on a padded child — curves will clash
  • Don’t skip transitions when elevation changes — abrupt lifts feel broken
  • Don’t cover titles or last nav items with an oversized edge fade — keep the fade short and pad the scroll content
  • Don’t use a flat opaque bar when the intent is glass — always mask the blur and fade the tint to transparent