Motion: Animate React Components (not just native DOM elements)

Created on 13 May 2020  路  5Comments  路  Source: framer/motion

I quite often use the @reach/dialog package for creating modals or other things things like off-screen mobile menus.

I'd like to animate the <DialogOverlay> and <DialogContent> components using Framer Motion.

In react-spring, I could do something like this:

const AnimatedDialogOverlay = animated(DialogOverlay);
const AnimatedDialogContent = animated(DialogContent);

Is there a way to do something similar in Framer Motion or can you only animate native DOM elements?

feature

Most helpful comment

Sure thing @lednhatkhanh, here is an example:

import React from 'react';
import { DialogOverlay, DialogContent } from '@reach/dialog';
import { AnimatePresence, motion } from 'framer-motion';

function Sidebar({ children, isSidebarOpen, setSidebarOpen }) {
  const handleDismiss = () => setSidebarOpen(false);

  const MotionDialogOverlay = motion.custom(DialogOverlay);
  const MotionDialogContent = motion.custom(DialogContent);

  return (
    <AnimatePresence>
      {isSidebarOpen && (
        <MotionDialogOverlay
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          exit={{ opacity: 0 }}
          onDismiss={handleDismiss}
        >
            <MotionDialogContent
              initial={{ x: '100%' }}
              animate={{ x: '0%' }}
              exit={{ x: '100%' }}
              transition={{ min: 0, max: 100, bounceDamping: 9 }}
              aria-label="Sidebar menu"
            >
              {children}
            </MotionDialogContent>
        </MotionDialogOverlay>
      )}
    </AnimatePresence>
  );
}

export { Sidebar };

All 5 comments

Sure, it's motion.custom(DialogOverlay)

Amazing, I was sure you would have thought of that already, but couldn't find it in the docs and my Google Fu failed me.
Thanks @InventingWithMonster!

@lukebennett88 I couldn't make framer-motion to work with ReachUI's Dialog, could you please provide an example, thank you.

Sure thing @lednhatkhanh, here is an example:

import React from 'react';
import { DialogOverlay, DialogContent } from '@reach/dialog';
import { AnimatePresence, motion } from 'framer-motion';

function Sidebar({ children, isSidebarOpen, setSidebarOpen }) {
  const handleDismiss = () => setSidebarOpen(false);

  const MotionDialogOverlay = motion.custom(DialogOverlay);
  const MotionDialogContent = motion.custom(DialogContent);

  return (
    <AnimatePresence>
      {isSidebarOpen && (
        <MotionDialogOverlay
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          exit={{ opacity: 0 }}
          onDismiss={handleDismiss}
        >
            <MotionDialogContent
              initial={{ x: '100%' }}
              animate={{ x: '0%' }}
              exit={{ x: '100%' }}
              transition={{ min: 0, max: 100, bounceDamping: 9 }}
              aria-label="Sidebar menu"
            >
              {children}
            </MotionDialogContent>
        </MotionDialogOverlay>
      )}
    </AnimatePresence>
  );
}

export { Sidebar };

@lukebennett88 Thank you so much!

Was this page helpful?
0 / 5 - 0 ratings