Foundations

Glass and motion

Glass for the control layer, springs, morphing and entrances

In the spirit of Liquid Glass in macOS 26 and iOS 26: content is solid, glass is only for the control layer above it, selection morphs as a drop and everything settles on a spring. Rules in DESIGN.md, “Glass and motion”

npx shadcn@latest add @umbra/glass @umbra/motion

Two layers

Content is solid: tiles, cards, text. Glass is only for the control layer that floats on top: the header on scroll, the action bar, menus. Scroll the list: there is always content under the glass

Design syncToday, 12:00
Beta reviewToday, 12:01
Interview: onboardingToday, 12:02
Sprint planningToday, 12:03
Metrics reviewToday, 12:04
Call with the lawyerToday, 12:05

Material

Tint --glass-tint with --glass-alpha, blur(var(--glass-blur)) saturate(180%), a highlight along the top edge, a thin --glass-edge rim, a soft --glass-shadow. Dense (--glass-alpha-dense) for small text over busy content

Design team meeting: beta on Friday, copy due Thursday. The summary was generated automatically, check the names

Design team meeting: beta on Friday, copy due Thursday. The summary was generated automatically, check the names

Regular

Summary

Dense

Small text and captions over busy content

Refraction

A lens along the edge: SVG feDisplacementMap in backdrop-filter, Chromium only (checked with @supports); Safari and Firefox get blur and saturate. Only on small elements: the selection indicator, the thumb, the toast. Move the cursor over the example

Design team meeting: beta on Friday, copy due Thursday. The summary was generated automatically, check the names

Design team meeting: beta on Friday, copy due Thursday. The summary was generated automatically, check the names

Concentricity

Inner radius equals outer radius minus padding. Controls use pills: the inner one follows the outer one

Nested 16

Tile 24, padding 8, inside 24 − 8 = 16

WeekMonth

Controls use pills: the inner pill with padding 4 follows the outer one

Accessibility

prefers-reduced-transparency gives a solid theme background without blur. APCA text contrast on glass is checked against the busiest background under it (worst case: a solid color under the glass). Below are the worst pairs from pnpm apca

Design team meeting: beta on Friday, copy due Thursday. The summary was generated automatically, check the names

Glass

Dense, small text, lightworst background: text, threshold 75101.2
Dense, small text, darkworst background: text, threshold 75106.4
Regular, large semibold, lightworst background: text, threshold 6064.9
Regular, large semibold, darkworst background: text, threshold 6090.4
Regular, small text, darkworst background: text, threshold 7590.4

Springs

--spring-snappy and --spring-smooth via CSS linear(): a spring with no visible overshoot, 4 % at most. Control layer only. prefers-reduced-motion: durations are 0, only opacity changes

--spring-snappy 0.35 s, overshoot 2 %

--spring-smooth 0.5 s, overshoot 0.2 %

--ease-out for comparison: enter

Morphing

The selection indicator doesn’t jump to the new spot, it morphs there as a drop: it stretches slightly along the direction of travel (about 1.08) and settles with a spring

Overlay enter

From blur(8px), scale 0.96 and transparency; exit is faster than enter (--t-exit, --ease-in)

Design team meeting: beta on Friday, copy due Thursday. The summary was generated automatically, check the names

Design team meeting: beta on Friday, copy due Thursday. The summary was generated automatically, check the names

Press

scale 0.97 and a stronger rim highlight while pressed

Design team meeting: beta on Friday, copy due Thursday. The summary was generated automatically, check the names

Page and theme changes

If a page loads over the network, the nav selection changes right on click and the content follows in --t-fast without blur: a View Transition would freeze the screen until load. When the new page is ready at once, use View Transitions: fade in from blur(6px), the title morphs. The theme changes with a circular reveal from the button. Try the sidebar items and the theme switch at the bottom left

Without View Transitions support and with prefers-reduced-motion the change is instant

Motion tokens

Curves and durations: entrance, exit and control-layer springs

One curve for entrances, one for exits. With “reduce motion” durations are 0: the ball snaps into place

ease-out

cubic-bezier(0.22, 1, 0.36, 1). All entrances and shifts

ease-in

cubic-bezier(0.4, 0, 1, 1). Exits

--t-fast 0.18 s: state change
--t-base 0.26 s: entrance
--t-page 0.24 s: screen change
--t-exit 0.28 s: card exit
--t-slow 0.5 s: panels, counters

Glass material @umbra/glass

Material classes, the dense variant, refraction, press and the Glass component

npx shadcn@latest add @umbra/glass

The glass material (styles/umbra/glass.css, added after base.css) and the Glass wrapper. Rules are in DESIGN.md, “Glass and motion”

  • .umbra-glass: --glass-tint tone at --glass-alpha, backdrop-filter: blur(var(--glass-blur)) saturate(180%), a highlight on the top edge, a thin --glass-edge border, a soft --glass-shadow
  • .umbra-glass-dense: dense glass (--glass-alpha-dense) for small text over busy backgrounds
  • .umbra-glass-soft: no shadow or edge; .umbra-glass-select: a selection indicator on a solid tile (--text tone at 8%)
  • .umbra-glass-refract: edge refraction (a lens) via SVG feDisplacementMap in backdrop-filter, Chromium only (checked with @supports); Safari and Firefox get only blur and saturate. Needs <GlassRefraction /> once per page. Small elements only: it’s expensive
  • .umbra-press: press, scale 0.97 and a stronger edge highlight
  • prefers-reduced-transparency and data-transparency="reduce" on <html>: a solid theme background without blur

The Glass component applies the base .glass* classes from theme-base (the same material), the refract and press props add classes from glass.css

When to use

  • Popover, menu, tooltip, dialog, a pill above content
  • dense: a notice card where text must read on any background
  • pop: menus and dialogs appearing out of blur

When not to use

  • Tile, nested surface, field: these surfaces are flat
  • Page header: Page turns on its glass
  • Notice: use the ready NoticeCard or Toast

Meetings

7 recordings this week

Team standupTue, 10:00 · 32 min
Designer interviewMon, 16:30 · 48 min
Call with contractorFri, 12:00 · 21 min
Mockup reviewThu, 11:00 · 54 min
Sprint retroWed, 17:00 · 40 min
Meeting with lawyerWed, 12:30 · 25 min
Metrics reviewTue, 15:00 · 36 min

Don’t

  • Glass on glass (umbra/glass-layer warning)
  • backdrop-filter on a tile (umbra/glass-layer warning)
  • Refraction on large panels
  • A gradient or glow instead of glass
  • Glass on an element in the page flow

Motion @umbra/motion

Springs, the morphing MorphIndicator, overlay entrances and theme switching

npx shadcn@latest add @umbra/motion

Control-layer motion in the spirit of Liquid Glass. Spring tokens are already in tokens.css (theme-base): --spring-snappy and --spring-smooth via linear(), durations --t-spring-snappy 0.35 s and --t-spring-smooth 0.5 s; with prefers-reduced-motion durations are 0. This item adds utilities (styles/umbra/motion.css, after base.css) and the MorphIndicator component

  • .umbra-pop-in / .umbra-pop-out: overlays appear from blur(8px), scale 0.96 and transparency; leaving is faster, over --t-exit with --ease-in
  • MorphIndicator: the selection drop doesn’t pop up in the new place, it morphs there; while moving it stretches along the direction (about 1.08) and settles with the --spring-snappy spring
  • .umbra-vt-title and the ::view-transition-* rules: new page content fades in from blur(6px) over --t-page, the title morphs if it’s on both pages
  • umbraThemeTransition(apply, origin): theme change as a circular reveal from the button

When to use

  • Selection indicator for tabs, chips, sidebar items, toggle thumb
  • Menu, tooltip, toast, dialog: appearing above content
  • Page and theme changes

When not to use

  • Content appearing in the flow: umbra-rise and umbra-appear from theme-base
  • The live character and showcases: they have their own loop

This item has no live example: it installs files or rules. See the “Code” tab to set it up

Do

  • Drop material from @umbra/glass: umbra-glass-select, with umbra-glass-refract on small ones
  • Springs only on the control layer

Don’t

  • Overshoot above 4%, custom curves instead of --spring-*
  • Springs on content in the flow or on text