Andrew
Andrew

Reputation: 795

Apply motion to react component Framer-Motion

I know that I can apply motion directly to element/HTMLtag like this:

<motion.div>some content</div>

But how can I apply it to this?

<Comp />

Without wrapping it inside another HTML element, like in React-Transition-Group library.

Framer API provides Frame component, but it acts like permanent additional HTML element with own styling, and it is messing my layout.

Upvotes: 10

Views: 16414

Answers (4)

BertC
BertC

Reputation: 2656

The accepted answer brought me on the right track.

But it was still a hassle to get everything working.

Therefore, I've created a full working example of Staggering elements which are React Components. It can be found on this Github link

This core of the solution looks like this:

import React from 'react'
import {motion} from "framer-motion";

interface ListElementInterface {
  name: string
}

// *** This is the React Component called in the list
// Pay attention to the ref type. Typescript is a b*tch
const ListElement = React.forwardRef(
  (props: ListElementInterface, ref: React.ForwardedRef<HTMLLIElement>) => {
    return (
      <li ref={ref}>{props.name}</li>
    )
  })


export const ReactList = () => {

    const datalist = [
      {name: 'John'},
      {name: "Alex"},
      {name: "Michael"},
      {name: 'Sandra'},
      {name: 'Mary'}
    ]

    const olVariants = {
      show: {
        transition: {
          staggerChildren: 0.2
        }
      }
    }

    const liVariants = {
      hidden: {opacity: 0, x: 100, transition: {duration: 0.5}},
      show: {opacity: 1, x: 0, transition: {duration: 0.5}}
    }


    // You need to create the Motion component.
    // Not possible to do something like <motion.ListElement...
    const FramerMotionListElement = motion(ListElement)

    return (
    <>
      <motion.ol
        variants={olVariants}
        initial="hidden"
        animate="show"
        className="simplelist"
      >
        {
          datalist.map((el) => {
            return (
              <FramerMotionListElement
                variants={liVariants}
                key={el.name}
                name={`React-${el.name}`}
              />
            )
          })
        }
      </motion.ol>
    </>
    )
}

Upvotes: 2

Andrew
Andrew

Reputation: 795

If anyone comes to this page seeking for the solution of how to apply motion from Framer-Motion library to your React Component and not the direct DOM element like "div" or "span", here it is:

motion.custom()

Example of use:

import { Link } from "react-router-dom"

const MotionLink = motion.custom(Link)

return <MotionLink />

As for today it is not mentioned in the official documentation, or it is in someplace deep and hard to find.

I had found it in BUG reports here, there is a Codesanbox that illustrates my example, created by the person who reported a bug.

Version 4.1.3 or higher

Edit: As mentioned by @Aleksandr K. below, use the following for Version >=4.1.3:

const MotionLink = motion(Link)

Upvotes: 30

user4944453
user4944453

Reputation:

motion.custom was deprecated as of v4.0 in favour of motion(Component) or motion("Component").

Your code would simply look like this

const MotionComp = motion(Comp)

return <MotionComp>some content</MotionComp>

Upvotes: 17

Dennis Vash
Dennis Vash

Reputation: 53934

Without using any internal fuctions, You just need to wrap it with any motion element:

<motion.div>
  <Comp />
</motion.div>

You can notice such behavior across examples in the docs, like of Side Menu example.

Upvotes: 8

Related Questions