Documentation

Documentation

React

Radix

Integrate Motion with Radix

Radix is one of the most popular component libraries for React, and it takes just a couple steps to use Motion for React for animations.

In this guide, we'll learn how to use motion components with Radix primitives, as well as specific setups for exit and layout animations.

Setup motion components

Most Radix components render and control their own DOM elements. But they also provide the asChild prop that, when set to true, will make the component use the first provided child as its DOM node instead.

By passing a motion component as this child, we can now use all of its animation props as normal:

<Toast.Root asChild>
  <motion.div
    initial={{ opacity: 0 }}
    animate={{ opacity: 1 }}
    layout

Exit animations

Many Radix components, like Toast or Tooltip, would be perfect for exit animations, but can't perform them without Motion's AnimatePresence.

AnimatePresence works by mounting and unmounting its children. This is how it tracks which components are exiting:

<AnimatePresence>
  {isOpen && <motion.div exit={{ opacity: 0 }} />}
</AnimatePresence>

By default Radix tends to control state like this isOpen internally. However, it provides some helper props for us to track or control this state externally.

For instance, the Tooltip component provides the open and onOpenChange props, which makes it easy to track the tooltip state:

const [isOpen, setOpen] = useState(false)

return (
  <Tooltip.Provider>
    <Tooltip.Root open={isOpen} onOpenChange={setOpen}>

Now we can use this state to conditionally render the tooltip contents.

<AnimatePresence>
  {isOpen && (
    <Tooltip.Portal forceMount>
      <Tooltip.Content asChild>
        <motion.div
            exit={{ opacity: 0 }}

You can see in the above example we use the forceMount prop on the Tooltip.Portal component. Because Radix expects all its children to be rendered at all times, when we're conditionally rendering children like this, setting forceMount to true allows our enter/exit animations to work correctly.

Layout animations

Layout animations also require this same pattern of hoisting state out of the component.

const [tab, setTab] = useState("account")

return (
  <Tabs.Root value={tab} onValueChange={setTab} asChild>
    <motion.div layout>

This is to ensure motion components know to perform layout animations when the state changes. You can even pass this state to layoutDependency for better performance.

<motion.div layout layoutDependency={tab}>

Motion+ examples

Motion+ is a one-time payment, lifetime membership that gains you access to the source code of an ever-growing library of premium examples, as well as premium components like Cursor and AnimateNumber.

Motion+ features examples for most Radix components:

A Motion+ membership will give you early access to features & content, access to our private Github and Discord, and more.

It's a one-time fee that grants lifetime access. No subscription necessary!

MOTION+

Premium React components

Motion+ is a one-time fee, lifetime membership that supports Motion and grants access to the source code of an ever-growing library of examples.


You also gain access to Cursor and AnimateNumber, two exclusive new React components. Check out what they can do: