Skip to content

Search pages

Jump to any page on the site.

Drawer

Slides in from its edge over a fading backdrop.

Live demo

The preset here changes the whole site. Slow motion and reduced motion change this stage only.

Frame by frame

Every frame of the movement, on top of each other. Wide gaps are fast. Ghosts past the dashed outline are overshoot. It updates with the preset.

24 frames383 ms
24 frames at 60 fps. Settles in 383 ms, overshoots 0.3%.

When to use

Side panels, filter sheets, and mobile navigation: a panel that comes in from an edge of the screen. The backdrop fades and the panel slides in from its edge on spring.default. The exit slides it back out with a fast tween, so closing never feels slow.

Slide from the edge the panel lives on. On a bouncy preset the panel overshoots its resting place, so let it run past the screen edge (or put a strip of its color there). Otherwise the overshoot opens a gap. Move focus into the panel at once, and keep it there until the panel closes. This site's mobile menu uses this recipe.

Recipe

Side panels and mobile navigation. The backdrop fades in. The panel slides in from its edge. Exit slides it back out, faster.

States of the drawer recipe
StatePropertyTokenNow
initialopacityliteral0
slideliteral0
animateopacityliteral1
slideliteral1
exitopacityliteral0
slideliteral0
transitionMovement (spring){spring.default}stiffness 511 · damping 40
transitionFade duration{duration.base}188ms
transitionFade easing{easing.enter}cubic-bezier(0, 0, 0, 1)
transitionExit duration{duration.fast}132ms
transitionExit easing{easing.exit}cubic-bezier(0.3, 0, 1, 1)

Tokens used

  • spring.default stiffness 511 · damping 40
  • duration.base 188ms
  • easing.enter cubic-bezier(0, 0, 0, 1)
  • duration.fast 132ms
  • easing.exit cubic-bezier(0.3, 0, 1, 1)

Code

/* drawer: Side panels and mobile navigation. The backdrop fades in. The panel slides in from its edge. Exit slides it back out, faster.
   Use: .motif-drawer-backdrop and .motif-drawer-panel (right edge; add data-side="left" for the left edge).
   They enter when mounted. To exit, set data-state="closed" and unmount after the transition.
   Bouncy presets overshoot: let the panel run past its edge, so the overshoot never opens a gap. */
.motif-drawer-backdrop {
  transition: opacity var(--motif-duration-base) var(--motif-ease-enter);
}
.motif-drawer-panel {
  transition: transform var(--motif-spring-default-duration) var(--motif-spring-default);
}
@starting-style {
  .motif-drawer-backdrop {
    opacity: 0;
  }
}
@starting-style {
  .motif-drawer-panel {
    transform: translateX(100%);
  }
}
@starting-style {
  .motif-drawer-panel[data-side="left"] {
    transform: translateX(-100%);
  }
}
.motif-drawer-backdrop[data-state="closed"] {
  opacity: 0;
  transition: opacity var(--motif-duration-fast) var(--motif-ease-exit);
}
.motif-drawer-panel[data-state="closed"] {
  transform: translateX(100%);
  transition: transform var(--motif-duration-fast) var(--motif-ease-exit);
}
.motif-drawer-panel[data-side="left"][data-state="closed"] {
  transform: translateX(-100%);
}

@media (prefers-reduced-motion: reduce) {
  /* drawer: the panel does not slide. It appears in place and fades. */
  .motif-drawer-panel,
  .motif-drawer-panel[data-state],
  .motif-drawer-panel[data-side][data-state] {
    transform: none;
    transition: opacity var(--motif-duration-fast) var(--motif-ease-standard);
  }
  @starting-style {
    .motif-drawer-panel {
      opacity: 0;
    }
  }
  .motif-drawer-panel[data-state="closed"] {
    opacity: 0;
  }
}

Reduced motion

  • No slide. The panel appears in place and fades with the backdrop. Focus still moves into the drawer at once.
  • Fades take 132ms (duration.fast), so the state change stays visible.
  • Turn on the Reduced motion box under the demo to preview it, or set your system to reduce motion.