October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsPC HealthRecommendedCrashes, freezes, slowdowns? Check your PC nowSpot repairable issues before they interrupt work.Check PCOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk6 min

React Dialog Exit Animation: Fixing Broken Transitions on Unmount

A React dialog that unmounts the instant it closes has nothing left to animate. Here is how to keep it mounted through the exit using Radix, Motion, React ViewTransition, or your own closing state.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A React dialog that vanishes the moment its open state turns false has no element left for an exit animation to play on. The fix is to keep the dialog mounted until the closing animation finishes. You can hand that job to the dialog primitive, to an animation library’s presence wrapper, to React’s ViewTransition, or to a closing state you manage yourself. The right choice depends on who owns unmounting in your stack, and the details differ by library and version.

Why the dialog disappears without animating

A pattern like {open && <Dialog />} removes the dialog node in the same commit that sets open to false. CSS can only animate an element that still exists in the DOM, so any fade-out or slide-out rule attached to the closing state never gets a frame to run. The symptom is a dialog that snaps shut even though the enter animation works.

As an Amazon Associate I earn from qualifying purchases.

Every working fix does one thing: it delays removal until the exit animation completes. The sections below cover the five common ways to do that.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose who owns unmounting first

Before changing code, decide which layer is responsible for keeping the dialog in the tree during the exit. The table compares the routes covered in this article.

Route Who owns unmounting Animation mechanism Placement requirement Key caveat
Radix Dialog with CSS keyframes Radix Dialog presence handling CSS keyframes keyed to data-state Standard Radix parts, no extra wrapper Radix’s guide describes keyframe animations; do not assume a transition-only rule behaves the same
Radix Dialog with a JavaScript library Your animation library, through forceMount JavaScript, for example React Spring forceMount on Portal, Overlay, and Content You must also remove the parts after the leave animation, or they stay in the DOM
Motion AnimatePresence AnimatePresence wrapper Motion exit prop Wrapper stays mounted; the animated element is its direct child If the wrapper sits inside the condition, it cannot see the removal
React ViewTransition React, during Transition updates View Transition exit and enter animations Only top-level ViewTransitions animate on exit and enter Not a drop-in replacement for a dialog library’s close lifecycle; stable in React 19.3
Manual closing state Your component state Any CSS or JavaScript Your code controls timing Full control, but you handle completion and fallbacks

Also check your installed React and dialog-library versions against their current documentation before you copy a pattern. Behavior in one release may not match another.

Option 1: Radix Dialog with CSS keyframes

Radix’s animation guide says CSS animation can handle both mount and unmount. It attributes the exit behavior to Radix suspending unmount while the animation plays. The guide’s example styles the overlay and content from their data-state values, open and closed, with a 300 ms fade-in and fade-out. That duration is illustrative, not a recommended value.

  1. Target the overlay and content with data-state selectors.
  2. Attach an opening animation to data-state="open".
  3. Attach a closing animation to data-state="closed", then verify in the browser that the element stays visible until the animation ends.
.dialog-content[data-state="open"] {
  animation: contentShow 300ms ease-out;
}
.dialog-content[data-state="closed"] {
  animation: contentHide 300ms ease-in;
}
@keyframes contentShow {
  from { opacity: 0; transform: translate(-50%, -48%) scale(0.96); }
  to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
@keyframes contentHide {
  from { opacity: 1; transform: translate(-50%, -50%) scale(1); }
  to   { opacity: 0; transform: translate(-50%, -48%) scale(0.96); }
}

The guide’s example uses keyframe animations. Do not assume a plain CSS transition on data-state behaves the same way. Confirm the primitive’s lifecycle behavior before relying on a transition’s end event.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Option 2: Radix Dialog with a JavaScript animation library

JavaScript animation libraries need control of the unmount phase. Radix provides forceMount on the Portal, Overlay, and Content parts so you can delegate mounting and unmounting to your library’s animation state. The guide demonstrates this with a React Spring transition state that conditionally renders the overlay and content.

  1. Add forceMount to Portal, Overlay, and Content.
  2. Render those parts only while the library reports the element as present.
  3. Confirm that the leave animation’s end actually removes the rendered parts. If they stay rendered after close, the dialog remains in the DOM.

This pattern is specific to the library in the guide. Do not add forceMount mechanically. The Radix Dialog API page, which lists version 1.2.0, documents the property on each part, but whether it fits your setup depends on your library’s API.

Option 3: Motion AnimatePresence

Motion’s AnimatePresence documentation says the component enables the exit prop by detecting when its direct children are removed from the React tree. The presence component has to stay mounted above the conditional child.

  1. Place AnimatePresence around the conditional, not inside the component that gets removed.
  2. Make the motion element the direct child of AnimatePresence.
  3. Give that element an exit prop.
<AnimatePresence>
  {open && (
    <motion.div key="dialog" exit={{ opacity: 0 }}>
      ...
    </motion.div>
  )}
</AnimatePresence>

The docs also cover removal caused by a key change and by removal of list items. For lists or keyed replacements, use stable, meaningful keys. A key that changes on every render will cause unexpected removals.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Option 4: React ViewTransition

React’s ViewTransition reference says enter and exit transitions activate when a ViewTransition is added or removed. It also sets a placement constraint: only top-level ViewTransitions animate on exit and enter, and a DOM node above the ViewTransition can prevent activation.

Updates that are not marked as Transitions do not trigger these animations. State changes inside startTransition are one qualifying case. React’s React 19.3 release post, dated September 9, 2026, says ViewTransition is stable in that release.

  • Confirm that your installed React version is 19.3 or later, and check the update path for your project.
  • Make sure the ViewTransition sits at the top level, with no DOM node above it that blocks activation.
  • Make sure the update that opens or closes the dialog runs inside startTransition.

ViewTransition animates the transition itself. It does not replace the dialog library’s own close handling, so check focus and modal behavior separately.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Option 5: Manage a closing state yourself

If you do not want a library to own unmounting, track three states instead of two: open, closing, and closed.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  1. On a close request, set the state to closing and keep the dialog rendered.
  2. Apply the closing animation while the state is closing.
  3. When the animation completes, set the state to closed and unmount the dialog.

Listening for animationend is the usual completion signal. It never fires if no animation runs, for example when a reduced-motion setting disables the effect or the element is hidden. Add a fallback timer that matches your animation duration so the dialog cannot get stuck in closing.

Keep focus and interaction correct during the exit

Radix’s documentation notes that modal dialog content normally traps focus. Radix’s source code comments that focus trapping is disabled once the dialog closes, even while it remains mounted during an exit. Do not assume every dialog library behaves this way.

When you keep a dialog mounted during its exit, check these points in the browser:

  • Focus returns to the element that opened the dialog once the exit finishes.
  • Keyboard users cannot reach controls in a dialog that is visually closing.
  • The closing element does not block clicks on the page underneath.

Troubleshooting checklist

  • The dialog snaps shut. Removal happens in the same commit that sets open to false, and nothing keeps the element mounted. Pick one of the routes above.
  • Enter animates, exit does not. The closing styles or exit prop are missing. Add a closed keyframe or an exit value.
  • The dialog stays on screen after closing. With forceMount, the parts never unmount after the leave animation. With a manual state, the closing state never resets.
  • AnimatePresence does not animate the exit. The wrapper is inside the conditional, the animated element is not a direct child, or the exit prop is missing.
  • ViewTransition does nothing. The ViewTransition is not top-level, a DOM node sits above it, the update is not a Transition, or React is older than 19.3.
  • A list item disappears without animating. The key is unstable or changes between renders.

Which route to choose

If you already use Radix Dialog and only need fade or scale effects, start with CSS keyframes. Use forceMount when your animation library needs to decide the timing. Use AnimatePresence when Motion already drives your animations. Choose ViewTransition only when your React version and update structure meet its requirements. Build a manual closing state when you need explicit control over completion and fallbacks.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.