Bounce only after a drag

Bounce when a drag supplied force; no bounce when a button did.

Emil Kowalski@emilkowalski
Made this with Motion's layout prop. Notice how when I drag it to dismiss there's a slight bounce at the end, but when I simply press the close button, there's no bounce at all. A drag requires some force, so adding a subtle bounce makes this transition feel more natural.
Jan 6, 2026Demo 1 ↓View on X ↗
Emil Kowalski@emilkowalski
swapped spring animaton for an ease-out one so it feels less abrupt.
Sep 23, 2026 · Linear dialogDemo 2 ↓View on X ↗

From emil-design-eng, “Spring animations”.

1. One card, two ways to close

Open a card, then drag it down, or press ×.

Same spring for every closeBad
Wednesday 24 SeptemberToday
Game of the Day Orbit Drift Thread a comet through gravity wells.
Orbit DriftPuzzle · Free

Drag down, or press ×.

Bounce follows forceGood
Wednesday 24 SeptemberToday
Game of the Day Orbit Drift Thread a comet through gravity wells.
Orbit DriftPuzzle · Free

Drag down, or press ×.

const easeOut = { duration: 0.3, ease: [0.23, 1, 0.32, 1] };
const bouncy  = { type: "spring", visualDuration: 0.4, bounce: 0.25 };

const [closedBy, setClosedBy] = useState<"drag" | "button">("button");

<motion.div
  layout
  transition={closedBy === "drag" ? bouncy : easeOut}
  drag="y"
  dragSnapToOrigin
  onDragEnd={(_, info) => {
    if (info.offset.y > 70 || info.velocity.y > 350) {
      setClosedBy("drag");
      setOpen(false);
    }
  }}
>
  <button aria-label="Close" onClick={() => { setClosedBy("button"); setOpen(false); }}>×</button>
</motion.div>

2. A dialog opened by a button

Press New issue and type right away.

SpringBad
Issues
  • FIN-212Reconcile Stripe payouts
  • FIN-209Close August books

spring, visualDuration 0.25s, bounce 0.30
Ease-outGood
Issues
  • FIN-212Reconcile Stripe payouts
  • FIN-209Close August books

transform 250ms var(--ease-out)
.dialog {
  opacity: 0;
  transform: scale(0.96);
  transition: opacity 200ms var(--ease-out), transform 250ms var(--ease-out);
}
.dialog[data-open] {
  opacity: 1;
  transform: scale(1);
}

Why it matters, pros and cons

Why it matters

A drag gives momentum, so overshoot confirms the throw. A click gives none.

Pros

  • Gestures feel physical, buttons feel precise.
  • Release velocity keeps the hand-off continuous.
  • One line decides it at the call site.

Cons

  • Two motion paths to design and test.
  • Above ~0.3 even a drag turns cartoonish.
  • Spring tails settle late; never gate focus on them.