Marquee · React

Endlessly moving text simply built with React and Framer.

Intermediate
Component
React
Framer
HTML
CSS
View Demo
Marquee · React thumbnail

Why Rebuild This In React?

In the previous guide: Marquee · Simple, we built our marquee using plain old HTML and CSS. This solution is simple and minimal, making it an excellent choice for most use-cases. In general, we want to keep things as stupid and simple as possible. The more libaries we involve, typically the more error-prone and computationally expensive the solution gets. But sometimes stakeholders have different requirements or maybe you want to make it feel more alive. For example, we may require the user to be able to hover and control the speed of the marquee. CSS doesn’t offer a good way to do this. This is where we benefit from converting our previous solution to using React and Framer which we’ll be doing in this guide. If you’re unfamiliar with Framer, I’ll give a brief overview on it later as well.

Setting Up Our HTML and CSS

For this we’ll be using Styled Components. Styled Components make for very convenient styling in React. If you’re interested in a separate guide on this, please let me know!

Using our previous guide: Marquee · Simple as inspiration, we’ll replicate the HTML and base CSS in React with Styled Components. We’ll create a new file called Marquee.jsx containing this:

import { styled } from "styled-components";

export const Marquee = ({ text }) => {
  // Duplicate the text here to have enough content to fill the screen
  const tickerText = `${text} ${text} ${text} ${text} ${text} ${text} `;

  return (
    <Container>
      <Track>
        {tickerText}
      </Track>
    </Container>
  );
};

const Container = styled.div`
  background: black;
  overflow: hidden;
`;

const Track = styled.div`
  font-size: 100px;
  color: white;
  width: max-content;
  white-space: pre;
`;

Setting Up Framer

The main concept of Framer is we define variants which are our different style states of our component. So in our previous CSS example, we have the beginning state and the animating state (that is infinitely looping). We can recreate these variants in Framer and define them in a variants object. Then we use a motion.div (provided by Framer), and pass it these variants as well as the active variant. Read through it and I’ll add comment along the way.

export const Marquee = ({ text }) => {
  // This is our identifier for our only animating state.
  const animationName = "marquee"

  const tickerText = `${text} ${text} ${text} ${text} ${text} ${text} `;

  const variants = {
    // The key here is our identifier for the animation state.
    [animationName]: {
      // We will be animating x to -50%.
      x: "-50%",

      // Now we can define the animation details here.
      transition: {
        x: {
          repeat: Infinity,
          repeatType: "loop",
          ease: "linear",
          duration: 30,
        },
      },
    },
  };

  return (
    <Container>
      // We convert our normal element into a `motion.div`. We add the variants we defined above.
      // And we use `whileInView` to apply our animation state while this element is in view.
      <Track as={motion.div} variants={variants} whileInView={animationName}>
        {tickerText}
      </Track>
    </Container>
  );
};

Additional Features: Reverse And Vertical

In the previous guide: Marquee · Simple, there were extra challenges to allow for reversing the direction and allowing for vertical text. I’ll go through these solutions now for you.

Reversing The Direction

For reversing, we just have to adjust the initial x and the animated x value. reverse can be passed in as a prop to our Marquee.jsx component.

// Pass in a new variable `reverse`.
export const Marquee = ({ text, reverse }) => {
  const tickerText = `${text} ${text} ${text} ${text} ${text} ${text} `;

  const variants = {
    animated: {
      // Adjust the animated value based on `reverse`.
      x: reverse ? "-50%" : 0,
      transition: {
        x: {
          repeat: Infinity,
          repeatType: "loop",
          ease: "linear",
          duration: 30,

          // Adjust the initial value based on `reverse`.
          ...(!reverse && { from: "-50%" }),
        },
      },
    },
  };
...

Animating The Text Vertically

For animating the text vertically, we can add an extra prop to our Marquee.jsx component called vertical. Using that we can control the animation axis (switching to Y from X). You then also need to pass our vertical prop into our Track Styled Component. From there, it can be used as a variable to conditonally apply new CSS.

export const Marquee = ({ text, reverse, vertical }) => {
  const tickerText = `${text} ${text} ${text} ${text} ${text} ${text} `;

  // Switch to animating the Y axis.
  const transformAxis = vertical ? "y" : "x";

  const variants = {
    animated: {
      // Dynamically use the correct axis.
      [transformAxis]: reverse ? "-50%" : 0,
      transition: {
        // Dynamically use the correct axis.
        [transformAxis]: {
          repeat: Infinity,
          repeatType: "loop",
          ease: "linear",
          duration: 30,
          ...(!reverse && { from: "-50%" }),
        },
      },
    },
  };

  return (
    <Container>
      <Track
        as={motion.div}
        variants={variants}
        whileInView="animated"

        // Pass our new prop into the `Styled Component`.
        {...{ vertical }}
      >
        {tickerText}
      </Track>
    </Container>
  );
};

const Container = styled.div`
  background: black;
  overflow: hidden;
`;

const Track = styled.div`
  font-size: 100px;
  color: white;
  width: max-content;
  white-space: pre;

  // Using this syntax, you gain access to the passed in variable.
  // We have awesome built in CSS support for converting text to vertical.
  ${({ vertical }) => {
    if (vertical) {
      return css`
        writing-mode: vertical-lr;
      `;
    }
  }}
`;

Next Up: Adding Custom Interaction

Congrats on finishing this tutorial! We’ve built marquee in simple HTML and CSS in the previous guide: Marquee · Simple. And now we’ve set it up in React with additional features to support reverse and vertical directions.

In the next guide we’ll focus on adding interaction to the marquee. There’s no extra challenges for this tutorial, but take some time to read about the few new libraries I introduced. They’re very commonly used in the web dev world, and I’ll be using them frequently.

  1. React: The industry leading JS libary used to create reusable components.
  2. Styled Components: Used to easily create styled HTML elements within React.
  3. Framer: Used to easily manage complex style animations within React.

As always, feel free to look at the demo page to see what you should expect from this guide.

View Demo