Categories
React

Framer Motion — Keyframes and Gestures

With the Framer Motion library, we can render animations in our React app easily.

In this article, we’ll take a look at how to get started with Framer Motion.

Animation

We can use the animate prop to specify how to animate an element.

For example, we can write:

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

export default function App() {
  return (
    <motion.div
      style={{ backgroundColor: "red", width: 100, height: 100 }}
      animate={{ scale: 2 }}
      transition={{ duration: 0.5 }}
    />
  );
}

We set animate to { scale: 2 } to double the size of the div.

The transition component is set to { duration: 0.5 } to set the duration of the animation in seconds.

Keyframes

We can add keyframes to create more complex animations.

For example, we can write:

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

export default function App() {
  return (
    <motion.div
      style={{ backgroundColor: "red", width: 100, height: 100 }}
      animate={{
        scale: [1, 2, 2, 1, 1],
        rotate: [0, 0, 270, 270, 0],
        borderRadius: ["30%", "30%", "50%", "50%", "40%"]
      }}
    />
  );
}

We add the scale property to set the quality to scale the div by in each frame.

rotate sets the rotation of the div in degrees in each frame.

borderRadius sets the border radius of the div in each frame.

Each entry an array is a quantity in a frame.

Variants

We can set predefined visual states in which a component can be in.

For instance, we can write:

import React, { useState } from "react";
import { motion } from "framer-motion";

const variants = {
  open: { opacity: 1, x: 0 },
  closed: { opacity: 0, x: "-100%" }
};

export default function App() {
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <button onClick={() => setIsOpen(!isOpen)}>toggle</button>
      <motion.nav animate={isOpen ? "open" : "closed"} variants={variants}>
        <p>foo</p>
      </motion.nav>
    </>
  );
}

to add animation when we toggle click on the toggle button to toggle the nav on and off.

The variants object have the style that the motion.nav can be in in different animation stages.

If it’s open , then opacity is 1, and x is 0.

And if it’s closed , then opacity is 0 and x is '-100%' .

Now we should see the ‘foo’ text move when we click on toggle.

Gesture Animations

We can listen to various gestures and animate elements when various gestures are applied.

For instance, we can write:

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

export default function App() {
  return (
    <>
      <motion.div
        whileHover={{ scale: 1.1 }}
        whileTap={{ scale: 0.9 }}
        style={{ backgroundColor: "red", width: 100, height: 100 }}
      ></motion.div>
    </>
  );
}

to listen for hovers with the whileHover prop.

And we listen to taps with the whileTap prop.

Then we set the scale to change the size of the div when those gestures are applied.

Conclusion

We can add complex animations with keyframes, and animate when gestures are applied with Framer Motion.

Categories
React

Framer Motion — Animations and Gestures

With the Framer Motion library, we can render animations in our React app easily.

In this article, we’ll take a look at how to get started with Framer Motion.

Motion Components

We can add motion components to add elements that we can animate.

For example, we can write:

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

export default function App() {
  return (
    <div className="App">
      <motion.div
        animate={{ scale: 0.5 }}
        style={{ backgroundColor: "red", width: 100, height: 100 }}
      />
    </div>
  );
}

to create a div that shrinks to half of the size that is specified in the style prop.

scale set to 0.5 does the shrinking with animation.

Animation

The animate prop lets us animate an element.

For example, we can write:

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

export default function App() {
  const variants = {
    hidden: { opacity: 0 },
    visible: { opacity: 1 }
  };

  return (
    <motion.div
      initial="hidden"
      animate="visible"
      variants={variants}
      style={{ backgroundColor: "red", width: 100, height: 100 }}
    />
  );
}

to create a div with the motion.div component.

And we animate from opacity 0 to opacity 1.

The initial prop has the name of the initial state of the div.

animate has the name of the style of the div after the animation.

The variants prop has the variants object, which specifies the animation style for each state.

Gestures

Framer Motion can direct hover, tap, pan and drag gestures automatically.

So we can do things to an element when these gestures are applied.

For example, we can write:

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

export default function App() {
  return (
    <motion.div
      drag="x"
      dragConstraints={{ left: -100, right: 100 }}
      whileHover={{ scale: 1.1 }}
      whileTap={{ scale: 0.9 }}
      style={{ backgroundColor: "red", width: 100, height: 100 }}
    />
  );
}

to let us drag the red div horizontally with the drag and dragConstraints props.

drag set to 'x' lets us drag horizontally. And dragConstraints lets us drag within the given bounds.

left sets the left limit and right sets the right limit.

whileHover has the style to change when we hover over the div.

whileTap lets us change the style when we tap on the div.

MotionValue

We can set motion values to set the style we want.

For example, we can write:

import React from "react";
import { motion, useMotionValue, useTransform } from "framer-motion";

export default function App() {
  const x = useMotionValue(0);
  const opacity = useTransform(x, [-200, 0, 200], [0, 1, 0]);

  return (
    <motion.div
      style={{ x, opacity, backgroundColor: "red", width: 100, height: 100 }}
      drag="x"
    />
  );
}

to let us animate the red div by changing the opacity when we drag it.

The useMotionValue prop creates a reactive property to watch form.

x is the horizontal position of the div.

The 2nd argument is the distance values.

And the 3rd argument is the opacity values that correspond to the distance values in the 2nd argument.

Conclusion

We can add basic animations with size and opacity changes and drag and drop effects with Framer Motion.

Categories
React

Add Animation to Our React App with the Framer Motion Library

With the Framer Motion library, we can render animations in our React app easily.

In this article, we’ll take a look at how to get started with Framer Motion.

Installation

We can install Framer Motion by running:

npm install framer-motion

Getting Started

We can create a div that moves by writing”

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

export default function App() {
  return (
    <div className="App">
      <motion.div
        animate={{ x: 100 }}
        style={{ width: 100, height: 100, backgroundColor: "red" }}
      />
    </div>
  );
}

We set the animate prop to an object with the x property to move it horizontally.

Draggable Element

We can make an element draggable by using the drag and dragConstraints props.

To use them, we write:

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

export default function App() {
  return (
    <div className="App">
      <motion.div
        drag="x"
        dragConstraints={{ left: -100, right: 100 }}
        style={{ width: 100, height: 100, backgroundColor: "red" }}
      />
    </div>
  );
}

We set drag to 'x' to let us drag and div horizontally.

And we add the dragConstraint prop to let us drag left 100px to right 100px.

We can animate lists by using the motion.ul and motion.li components.

For example, we can write:

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

export default function App() {
  const list = { hidden: { opacity: 0 } };
  const item = { hidden: { x: -10, opacity: 0 } };

  return (
    <motion.ul animate="hidden" variants={list}>
      <motion.li variants={item}>foo</motion.li>
      <motion.li variants={item}>bar</motion.li>
      <motion.li variants={item}>baz</motion.li>
    </motion.ul>
  );
}

We set the variants prop to objects to let us hide the elements with various styles.

animate is set to hidden , which is the name of the animation.

We set the opacity to 0 to hide the items.

The x property is set to -10 to move the li elements 10px to the left.

We can combine drag and drop with animation by using various hooks that comes with Framer Motion.

For example, we can write:

import React from "react";
import { motion, useMotionValue, useTransform } from "framer-motion";

export default function App() {
  const x = useMotionValue(0);
  const opacity = useTransform(x, [-100, 0, 100], [0, 1, 0]);

  return (
    <motion.div
      drag="x"
      style={{ x, opacity, width: 100, height: 100, backgroundColor: "red" }}
    />
  );
}

to create a red div that animate when we drag it.

The useMotionValue prop lets us create a distance value that we pass into the style prop.

useTransform lets us change the opacity as the div is animated.

The first argument is the quantity to change.

The 2nd argument is the distance values.

And the 3rd argument is the opacity values that correspond to the distance values in the 2nd argument.

So when we drag left or right, the opacity of the div becomes 0.

Conclusion

We can add basic animations and drag and drop effects with Framer Motion.

Categories
Gatsby.js

Gatsby.js — Scroll Position, Dynamic Navigation, and Link States

Gatsby is a static web site framework that’s based on React.

We can use it to create static websites from external data sources and more.

In this article, we’ll look at how to create a site with Gatsby.

Scroll Restoration

We can restore the scrolling position after refresh with Gatsby.

For example, we can write:

import React from "react"
import { useScrollRestoration } from "gatsby"

const IndexPage = () => {
  const ulScrollRestoration = useScrollRestoration(`page-component-ul-list`)

return (
    <ul style={{ height: 200, overflow: `auto` }} {...ulScrollRestoration}>
      {Array(100).fill().map((_, i) => i).map(n => (
        <li key={n}>{n}</li>
      ))}
    </ul>
  )
}

export default IndexPage

We use the useScrollRestoration hook with the 'page-component-ul-list' argument to let us create an object to restore the scrolling position.

Then we spread that object’s properties as props of the ul to let us restore the scrolling position.

Location Data from Props

We can get location data from props.

To do this, we write:

gatsby-config.js

module.exports = {
  siteMetadata: {
    siteURL: 'http://example.com'
  }
}

src/pages/foo.js

import React from "react"
import { graphql } from "gatsby"

const FooPage = ({ location, data }) => {
  const canonicalUrl = data.site.siteMetadata.siteURL + location.pathname
  return <div>The URL of this page is {canonicalUrl}</div>
}

export const query = graphql`
  query PageQuery {
    site {
      siteMetadata {
        siteURL
      }
    }
  }
`

export default FooPage

We get the siteMetadata.siteURL from the gatsby-config.js via the GraphQL query.

Then we get the location prop’s pathname property to get the path to the FooPage .

So we should see:

The URL of this page is http://example.com/foo

displayed when we go to http://localhost:8000/foo.

Providing State to a Link Component

We can provide state to a Link component.

For example, we write:

src/pages/index.js

import { Link } from "gatsby"
import React from "react"

const IndexPage = () => {
  return <>
    <div>hello world</div>
    <Link
      to={'/foo'}
      state={{ id: 1 }}
    >
      go to foo
    </Link>
  </>
}

export default IndexPage

src/pages/foo.js

import React from "react"

const FooPage = ({ location }) => {
  const { state = {} } = location
  const { id } = state
  return <div>id: {id}</div>
}

export default FooPage

We pass an object into the state prop.

Then in FooPage , we get the location prop’s state.id property to get the id property that we passed into the state prop.

Dynamic Navigation

We can add navigation dynamically with Gatsby.

To do this, we write:

module.exports = {
  siteMetadata: {
    title: 'Gatsby Starter',
    menuLinks: [
      {
        name: 'home',
        link: '/'
      },
      {
        name: 'foo',
        link: '/foo'
      }
    ]
  },
  plugins: []
}

src/components/layout.js

import React from "react"
const { StaticQuery, Link } = require("gatsby");

const Header = ({ siteTitle, menuLinks }) => (
  <header
    style={{
      background: "green",
      marginBottom: "1.45rem",
    }}
  >
    <div>
      <h1 style={{ margin: 5, flex: 1 }}>
        <Link
          to="/"
          style={{
            color: "white",
            textDecoration: "none",
          }}
        >
          {siteTitle}
        </Link>
      </h1>
      <div>
        <nav>
          <ul style={{ display: "flex", flex: 1 }}>
            {menuLinks.map(link => (
              <li
                key={link.name}
                style={{
                  listStyleType: `none`,
                  padding: `1rem`,
                }}
              >
                <Link style={{ color: `white` }} to={link.link}>
                  {link.name}
                </Link>
              </li>
            ))}
          </ul>
        </nav>
      </div>
    </div>
  </header>
)

const Layout = ({ children }) => (
  <StaticQuery
    query={graphql`
        query SiteTitleQuery {
          site {
            siteMetadata {
              title
              menuLinks {
                name
                link
              }
            }
          }
        }
      `}
    render={data => (
      <>
        <Header menuLinks={data.site.siteMetadata.menuLinks} siteTitle={data.site.siteMetadata.title} />
        <div
          style={{
            margin: '0 auto',
            maxWidth: 960,
            padding: '0px 1.0875rem 1.45rem',
            paddingTop: 0,
          }}
        >
          {children}
        </div>
      </>
    )}
  />
)

export default Layout;

src/pages/index.js

import { Link } from "gatsby"
import React from "react"
import Layout from "../components/layout"

const IndexPage = () => {
  return <>
    <Layout>
      <div>hello world</div>
    </Layout>
  </>
}

export default IndexPage

src/pages/foo.js

import React from "react"
import Layout from "../components/layout"

const FooPage = () => {
  return <div>
    <Layout>
      <div>foo</div>
    </Layout>
  </div>
}

export default FooPage

We add the menuLinks array into gatsby-config.js to add the data for the links.

Then in layout.js , we get the link data and then render them.

The Header component takes the siteTitle and menuLinks props and render the data into HTML.

siteTitle has the title of the site.

menuLinks is an array of data that we have from gatsby-config.js ‘s menuLinks property.

Then in the Layout component, we add the StaticQuery component to make the query for the menu link data.

The render prop has the result of the query in the data parameter.

And we render the links and title with the Header component.

The div has the child components that we have inside the Layout component tags.

Conclusion

We can restore the scroll position after refresh with Gatsby.

Also, we can get location data from props.

And we can create links dynamically from the site’s metadata.

Categories
Gatsby.js

Gatsby.js — Page Transitions

Gatsby is a static web site framework that’s based on React.

We can use it to create static websites from external data sources and more.

In this article, we’ll look at how to create a site with Gatsby.

Transitions

We can add transitions when navigation to a different page.

To do this, we add the gsap package and gatsby-plugin-transition-link plugins.

We install them by running:

npm i gsap gatsby-plugin-transition-link

Then in gatsby-config.js , we add:

module.exports = {
  plugins: [
    `gatsby-plugin-transition-link`
  ],
}

Then in our pages, we write:

src/pages/index.js

import React from "react"
import AniLink from "gatsby-plugin-transition-link/AniLink"

const IndexPage = () => {
  return <>
    <div>hello world</div>
    <AniLink paintDrip to="/foo">
      Go to foo
    </AniLink>
  </>
}

export default IndexPage

src/pages/foo.js

import React from "react"
import AniLink from "gatsby-plugin-transition-link/AniLink"

const FooPage = () => {
  return <>
    <div>hello world</div>
    <AniLink paintDrip to="/">
      Go to Index
    </AniLink>
  </>
}

export default FooPage

The AniLink component is a Link component that lets us show transition effects when we click on it.

paintDrip is the effect name. It shows a blue color flowing down the screen.

to has the URL we want to go to.

Custom Transitions

We can also add our own transitions.

We install React Post by running:

npm i react-post

Then we write:

import React from "react"
import { TransitionState } from "gatsby-plugin-transition-link"
import posed from 'react-pose';

const Box = posed.div({
  hidden: { opacity: 0 },
  visible: { opacity: 0.6 },
})

const IndexPage = () => {
  return <>
    <TransitionState>
      {({ transitionStatus, exit, entry, mount }) => {
        console.log("current page's transition status is", transitionStatus)
        console.log("exit object is", exit)
        console.log("entry object is", entry)
        return (
          <Box
            className="box"
            pose={
              mount
                ? 'visible'
                : 'hidden'
            }
          >
            <div>hello world</div>
          </Box>
        )
      }}
    </TransitionState>
  </>
}

export default IndexPage

We use react-pose to create the Box component.

The Box component has the transition effect when the animation begins and ends respectively.

Then we add the TransitionState component to add our transition.

transitionStatus has the status of the transition.

exit has an object with the state of the transition when the transition ends.

entry has an object with the state of the transition when the transition starts.

mount is true when the page is mounted or has mounted.

We set the 'visible' or 'hidden' class when mounted is true or false respectively.

Then ‘hello world’ should end up with opacity being 0.6 at the end.

Excluding Elements from Page Transitions

We can exclude elements from page transitions.

To do this, we write:

module.exports = {
    plugins: [
       {
          resolve: "gatsby-plugin-transition-link",
          options: {
              layout: require.resolve(`./src/components/Layout.js`)
            }
       }
    ]
];

The src/components/Layout.js is excluded from any page transition effects.

Conclusion

We can add page transition effects to our pages with Gatsby.