paint-brush
Learn How to Create A Simple Carousel with React.jsby@AlexDevero
1,339 reads
1,339 reads

Learn How to Create A Simple Carousel with React.js

by Alex DeveroAugust 28th, 2017
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

Have you ever wanted to create a simple carousel in React.js? In that case, you are on the right place. In this easy tutorial, we will create a simple carousel you can then take and use anywhere you want and with any content you want. I tried to make this tutorial simple. So, even beginners and people wanting to learn React.js should be able to complete it. I hope this tutorial will help you learn about React.js and get started with it in an enjoyable way.

People Mentioned

Mention Thumbnail
Mention Thumbnail

Companies Mentioned

Mention Thumbnail
Mention Thumbnail
featured image - Learn How to Create A Simple Carousel with React.js
Alex Devero HackerNoon profile picture

Have you ever wanted to create a simple carousel in React.js? In that case, you are on the right place. In this easy tutorial, we will create a simple carousel you can then take and use anywhere you want and with any content you want. I tried to make this tutorial simple. So, even beginners and people wanting to learn React.js should be able to complete it. I hope this tutorial will help you learn about React.js and get started with it in an enjoyable way.

Table of Contents:

Briefing

Workspace and HTML

SASS

Styling the carousel component and its content

Styling carousel indicators

Putting it together

React.js

Preparing carousel functionality

From HTML to React

Putting it together

Closing thoughts on creating a simple carousel and learning React.js

Demo on Codepen.

Briefing

Let’s start with briefly describing the goals for this React.js carousel tutorial. Our main goal is to create a simple carousel. This carousel will contain a number of slides, two directional arrows on its sides and finally an indicator (something like a dot) for each slide. User will be able to cycle through slides either by using arrows or by clicking on one of the indicators below the carousel. Also, when user reaches the last slide and click on “right” arrow, carousel will show the first slide.

The same is true for situation when user is on the first slide and clicks on the “left” arrow. Carousel will show the last slide. In other words, user will be able to cycle through slides infinitely in both directions. In the beginning, I wanted to implement a functionality that would allow the carousel to cycle through slides automatically, in specific intervals. However, a lot of people don’t consider this to be a good practice in UX. And, I agree.


Still, if you would like to have this functionality, you can take it as a challenge to test your skills. In the end, the best way to learn anything is by doing it. This is especially true about coding. So, take charge and put your new skills to the test. And, that being said, we can start.Workspace and HTML

Workspace and HTML

The first step is setting up our workspace. Then, we will put together the HTML code that is necessary for this carousel tutorial. Luckily, because we are working with React.js, that will be a one-liner. Anyway, back to the workspace. React.js requires two libraries in order to work as it should. These libraries are React and React-DOM. In this carousel tutorial, we will use CDN to get both of them. These are all necessary assets we need to build our carousel.

Aside from these required assets, I also used some additional, mainly for styling purposes. These assets are web fonts Roboto and Open Sans, both are available on Google Fonts. Next, I also used Font Awesome for directional arrow icons we are going to use in our carousel. Finally, I used babel compiler so we can use the latest JavaScript syntax without worrying that something will not work. Also, working with React.js is easier when you use babel.

The second step we will make is getting our HTML code ready. This will be very quick since the majority of our code will be in Reat.js (or JavaScript). All we need to do is prepare one div element. In the end, we will use this element as a “place” in DOM where we will render carousel React component. Let’s also give this div some class so we can find it easily, such as “carousel-container“. And, this is all for HTML.

Code:

<div class="carousel-container"></div>

SASS

The third step is adding some styles. Otherwise, our carousel will work, but its layout will be broken. As a result, it will be pretty much unusable. Meaning, all slides will be visible, stacked one under the other. Let’s start with the outer layer of our carousel and move to the center. First, let’s reset some default properties of ul element, such as padding, margin and list-style-type. Then, we can continue by styling the “carousel-cotainer” div, our only piece of HTML code.

We will set its display property to “flex”, flex-direction to “column”, center the content and set min-height. This is necessary if we want to prevent the arrows on sides from “jumping” up and down every time the next slide has a different height than the previous one. Otherwise, you can ignore these styles and move on to styling carousel itself.

Code:

// SASS variable for media query breakpoint
$breakpoint-desktop: 992px;

// Resetting default styles
ul {
  padding: 0;
  margin: 0;
  list-style-type: none;
}

// Fix for jumping arrows
.carousel-container {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 210px;
}

Carousel itself needs only one line of CSS. We need to set its position to “relative”. Then, we can move on and add some styles for slides. We will center all slides using margin, center the content using text-align property, set some max-width and set display to “none”. Then, we will set display to “block” for the slide that is currently active. I also added some padding on left and right for smaller screens so the arrows don’t overlap the text.

Next, we can add some styles for the content of our slides. In this tutorial, each slide will contain some short text, author of the text and its source. I chose Open Sans and bigger font-size for the content, with small margin on the bottom, and Roboto and smaller font-size for the author and source. When we are done with this, we can move on to directional arrows.

We will set position of both to “absolute”, display to “block”, color to “#111”, cursor to “pointer” and opacity to “.75”. Then, we will use combination of top and transform properties to center them on the vertical axis. Next, we will remove outline on focus and increase the opacity on hover. We can also use transition to make the change in opacity smoother. Finally, we will use left (for left arrow) and right (for right arrow) properties to position each arrow on horizontal axis.

Code:

.carousel {
  position: relative;
}

// Carousel slides
.carousel__slide {
  margin-right: auto;
  margin-left: auto;
  display: none;
  max-width: 900px;
  list-style-type: none;
  text-align: center;

  @media (max-width: 991px) {
    padding-right: 60px;
    padding-left: 60px;
  }

  &--active {
    display: block;
  }
}

// Content of slides
.carousel-slide__content {
  margin-bottom: 19px;
  font-family: 'Open Sans', 'Trebuchet MS', sans-serif;
  font-size: 16px;

  @media (max-width: $breakpoint-desktop - 1px) {
    font-size: 18px;
  }
}

.carousel-slide__author,
.carousel-slide__source {
  font-family: 'Roboto', arial, sans-serif;
  font-size: 14px;

  @media (min-width: $breakpoint-desktop) {
    font-size: 16px;
  }
}

.carousel-slide__source {
  font-style: italic;
  color: #888;
}

// Carousel arrows
.carousel__arrow {
  position: absolute;
  top: 50%;
  display: block;
  color: #111;
  cursor: pointer;
  opacity: .75;
  transform: translateY(-50%);
  transition: opacity .15s cubic-bezier(.4, 0, 1, 1);

  &:focus {
    outline: 0;
  }

  &:hover {
    opacity: .5;
  }

  &--left {
    left: 32px;
  }

  &--right {
    right: 32px;
  }
}

The last part of our carousel are indicators on the bottom. Instead of using dots, I decided to use subtle lines. These lines will be right under the slides and centered on the horizontal axis. We will use flexbox to achieve this. The width of these lines will be “24px” while height “3px”. We will set the display property to “block” and set cursor to “pointer”. The default background-color of these lines will be “#111”, with opacity set to “.15”.

On hover the opacity will increase to “.5”. And, we can again use transition to make this change smoother. Currently active line will have opacity of “.75”, for both, default state as well as hover.

Code:

// Carousel indicators
.carousel__indicators {
  display: flex;
  flex-direction: row;
  justify-content: center;
  margin-top: 20px;

  li {
    &:nth-of-type(n + 2) {
      margin-left: 9px;
    }
  }
}

.carousel__indicator {
  display: block;
  width: 24px;
  height: 3px;
  background-color: #111;
  cursor: pointer;
  opacity: .15;
  transition: opacity .15s cubic-bezier(.4, 0, 1, 1);

  &:hover {
    opacity: .5;
  }

  &--active {
    &,
    &:hover {
      opacity: .75;
    }
  }
}

Putting it together

This is all we need when it comes to styling. Below is the whole content of our SASS stylesheet.

Code:

// SASS variable for media query breakpoint
$breakpoint-desktop: 992px;

// Resetting default styles
ul {
  padding: 0;
  margin: 0;
  list-style-type: none;
}

// Fix for jumping arrows
.carousel-container {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 210px;
}

.carousel {
  position: relative;
}

// Carousel slides
.carousel__slide {
  margin-right: auto;
  margin-left: auto;
  display: none;
  max-width: 900px;
  list-style-type: none;
  text-align: center;

  @media (max-width: 991px) {
    padding-right: 60px;
    padding-left: 60px;
  }

  &--active {
    display: block;
  }
}

// Content of slides
.carousel-slide__content {
  margin-bottom: 19px;
  font-family: 'Open Sans', 'Trebuchet MS', sans-serif;
  font-size: 16px;

  @media (max-width: $breakpoint-desktop - 1px) {
    font-size: 18px;
  }
}

.carousel-slide__author,
.carousel-slide__source {
  font-family: 'Roboto', arial, sans-serif;
  font-size: 14px;

  @media (min-width: $breakpoint-desktop) {
    font-size: 16px;
  }
}

.carousel-slide__source {
  font-style: italic;
  color: #888;
}

// Carousel arrows
.carousel__arrow {
  position: absolute;
  top: 50%;
  display: block;
  color: #111;
  cursor: pointer;
  opacity: .75;
  transform: translateY(-50%);
  transition: opacity .15s cubic-bezier(.4, 0, 1, 1);

  &:focus {
    outline: 0;
  }

  &:hover {
    opacity: .5;
  }

  &--left {
    left: 32px;
  }

  &--right {
    right: 32px;
  }
}

// Carousel indicators
.carousel__indicators {
  display: flex;
  flex-direction: row;
  justify-content: center;
  margin-top: 20px;

  li {
    &:nth-of-type(n + 2) {
      margin-left: 9px;
    }
  }
}

.carousel__indicator {
  display: block;
  width: 24px;
  height: 3px;
  background-color: #111;
  cursor: pointer;
  opacity: .15;
  transition: opacity .15s cubic-bezier(.4, 0, 1, 1);

  &:hover {
    opacity: .5;
  }

  &--active {
    &,
    &:hover {
      opacity: .75;
    }
  }
}

React.js

We are in the final part of this tutorial. Now, our job is to create React component for our carousel and make it work, so to speak. I decided to write the whole carousel as one big component. However, be aware that this is not exactly the best practice. It is better to create small components and then use each individually as needed. For now, I decided to make it a little bit easier and faster. And, the truth is that I am not so good in React.js yet. You know, we all are learning.

Preparing the workplace

First, we will save Component from React and render method from React-DOM into consts so we can use them quickly when we need. And, we can do the same with carousel container div. Finally, we will create one more const that will store the data for our carousel. We will use an array with one object for every slide. Each object will contain “content”, “author” and “source” keys with some random values. We will use these values to populate our slides with data.

Code:

const { Component } = React;
const { render } = ReactDOM;

const carouselContainer = document.querySelector(".carousel-container");

// Data for carousel
const carouselSlidesData = [
  {
    content:
      "Tomorrow, you will be released. If you are bored of brawling with thieves and want to achieve something there is a rare blue flower that grows on the eastern slopes. Pick one of these flowers. If you can carry it to the top of the mountain, you may find what you were looking for in the first place.",
    author: "Bane",
    source: "facebook"
  }, {
    content:
      "You have learn to bury your guilt with anger. I will teach you to confront it and to face the truth.",
    author: "Ra's Al Ghul",
    source: "Snapchat"
  }, {
    content:
      "Introduce a little anarchy, upset the established order and everything becomes chaos. I'm an agent of chaos. Oh, and you know the thing about chaos? It's fair.",
    author: "Joker",
    source: "facebook"
  }, {
    content:
      "I can't do that as Bruce Wayne... as a man. I'm flesh and blood. I can be ignored, destroyed. But as a symbol, I can be incorruptible, I can be everlasting.",
    author: "Bruce Wayne",
    source: "facebook"
  }, {
    content:
      "But it's not who you are underneath... it's what you do that defines you.",
    author: "Rachel Dawes",
    source: "twitter"
  }, {
    content:
      "When their enemies were at the gates the Romans would suspend democracy and appoint one man to protect the city. It wasn't considered an honor, it was a public service.",
    author: "John Blake",
    source: "Google+"
  },
  {
    content:
      "Master Wayne, you've been gone a long time. You look very fashionable. Apart from the mud.",
    author: "Alfred Pennyworth",
    source: "twitter"
  }
];

The next step is building the carousel. For this, we will create new class “Carousel” that extends the React Component we store in const. We will start with a constructor method that will contain super and the state of Carousel component. Inside it, we will define new key “activeIndex” and set it to “0”. This is the index of active slide when carousel is loaded, or the first slide.

Next, we will create new method “goToSlide” that takes “index” as a parameter. This method will access the state of Carousel component and change the value of “activeIndex” to the value of “index”. Then, we will create two more methods, goToPrevSlide() and goToNextSlide(). We will use these methods when user clicks on one of the carousel arrows to either show the previous or next slide. These methods will look very similar.

Both will load and store the value of “activeIndex” from Carousel state. Next, they will store the slides data from props and also the number of slides (the length of the slides array). The goToPrevSlide method will then check if the index (“activeIndex”) is smaller than 1. If so, then it will set the index to the index of the last slide (slidesLength). Otherwise, it will decrease the index by 1 and use it as a new value for “activeIndex” key inside Carousel state.

The goToNextSlide() method will do the same thing, but with small differences and in the opposite direction. It will also load and store the value of “activeIndex” from Carousel state, just like goToPrevSlide() method. And, it will store the slides data from props as well. However, it will not care about the last slide, but about the last but slide (slides.length — 1).

Then, it will check if the index (“activeIndex”) is equal to the value of slidesLength const. If so, it will set the value of the “index” to “-1” and load the first slide. Otherwise it will increase the value of the index by 1 and use it as a new value for “activeIndex” key inside Carousel state.

Code:

// Carousel wrapper component
class Carousel extends Component {
  constructor(props) {
    super(props);

    this.state = {
      activeIndex: 0
    };
  }

  goToSlide(index) {
    this.setState({ activeIndex: index });
  }

  goToPrevSlide(e) {
    e.preventDefault();

    let index = this.state.activeIndex;
    let { slides } = this.props;
    let slidesLength = slides.length;

    if (index < 1) {
      index = slidesLength;
    }

    --index;

    this.setState({
      activeIndex: index
    });
  }

  goToNextSlide(e) {
    e.preventDefault();

    let index = this.state.activeIndex;
    let { slides } = this.props;
    let slidesLength = slides.length - 1;

    if (index === slidesLength) {
      index = -1;
    }

    ++index;

    this.setState({
      activeIndex: index
    });
  }
}

From HTML to React

This is the final step. We will now create the structure for our carousel. We will wrap this code inside render() method. The structure is following: there will be one div with class “carousel”. This will contain two anchor elements (arrows) with one span element in each (icons). Then, there will be one unordered list with class “carousel__slides”. This list will use map() method to cycle through slides data array and generate one list item for each slide. Every list item will contain two p elements, one for content and one from author and source.

Author will be wrapped inside strong element and source inside small. Slide that is currently active (its index is equal to this.state.activeIndex) will have “carousel__slide–active” class. Next, there will be one more unordered list at the bottom for carousel indicator, with class “carousel__indicators”. Here, we will again use map() method to through slides data array. Now, each list item will contain one anchor element with class “carousel__indicator”. Active indicator (its index is equal to this.state.activeIndex) will have “carousel__indicator–active” class.

Now, we need to add functionalities to specific elements. In other words, click on the left arrow will trigger goToPrevSlide() method while click on the right goToNextSlide(). Finally, click on any carousel indicator will trigger goToSlide() method. I almost forgot. This is the last step. We need to use render() method to render the Carousel component inside the “carousel-container” div. One last thing we need to remember use the “carouselSlidesData” as a value for “slide” prop.

Code:

// Carousel wrapper component
class Carousel extends Component {
  render() {
    return (
      <div className="carousel">
        <a
          href="#"
          className="carousel__arrow carousel__arrow--left"
          onClick={e => this.goToPrevSlide(e)}
        >
          <span className="fa fa-2x fa-angle-left" />
        </a>

        <ul className="carousel__slides">
          {this.props.slides.map((slide, index) =>
            <li
              className={
                index == this.state.activeIndex
                  ? "carousel__slide carousel__slide--active"
                  : "carousel__slide"
              }
              key={index}
            >
              <p className="carousel-slide__content">{slide.content}</p>

              <p>
                <strong className="carousel-slide__author">
                  {slide.author}
                </strong>,
                {" "}<small className="carousel-slide__source">
                  {slide.source}
                </small>
              </p>
            </li>
          )}
        </ul>

        <a
          href="#"
          className="carousel__arrow carousel__arrow--right"
          onClick={e => this.goToNextSlide(e)}
        >
          <span className="fa fa-2x fa-angle-right" />
        </a>

        <ul className="carousel__indicators">
          {this.props.slides.map((slide, index) =>
            <li key={index}>
              <a
                className={
                  index == this.state.activeIndex
                    ? "carousel__indicator carousel__indicator--active"
                    : "carousel__indicator"
                }
                onClick={e => this.goToSlide(index)}
              />
            </li>
          )}
        </ul>
      </div>
    );
  }
}

// Render Carousel component
render(<Carousel slides={carouselSlidesData} />, carouselContainer);

Putting it together

We have HTML container and we have styles. And now, we also have React component for our carousel. This is all we need to get our React carousel up and running. Below is the whole code we just discussed in one piece.

Code:

const { Component } = React;
const { render } = ReactDOM;

const carouselContainer = document.querySelector(".carousel-container");

// Data for carousel
const carouselSlidesData = [
  {
    content:
      "Tomorrow, you will be released. If you are bored of brawling with thieves and want to achieve something there is a rare blue flower that grows on the eastern slopes. Pick one of these flowers. If you can carry it to the top of the mountain, you may find what you were looking for in the first place.",
    author: "Bane",
    source: "facebook"
  }, {
    content:
      "You have learn to bury your guilt with anger. I will teach you to confront it and to face the truth.",
    author: "Ra's Al Ghul",
    source: "Snapchat"
  }, {
    content:
      "Introduce a little anarchy, upset the established order and everything becomes chaos. I'm an agent of chaos. Oh, and you know the thing about chaos? It's fair.",
    author: "Joker",
    source: "facebook"
  }, {
    content:
      "I can't do that as Bruce Wayne... as a man. I'm flesh and blood. I can be ignored, destroyed. But as a symbol, I can be incorruptible, I can be everlasting.",
    author: "Bruce Wayne",
    source: "facebook"
  }, {
    content:
      "But it's not who you are underneath... it's what you do that defines you.",
    author: "Rachel Dawes",
    source: "twitter"
  }, {
    content:
      "When their enemies were at the gates the Romans would suspend democracy and appoint one man to protect the city. It wasn't considered an honor, it was a public service.",
    author: "John Blake",
    source: "Google+"
  },
  {
    content:
      "Master Wayne, you've been gone a long time. You look very fashionable. Apart from the mud.",
    author: "Alfred Pennyworth",
    source: "twitter"
  }
];

// Carousel wrapper component
class Carousel extends Component {
  constructor(props) {
    super(props);

    this.state = {
      activeIndex: 0
    };
  }

  goToSlide(index) {
    this.setState({ activeIndex: index });
  }

  goToPrevSlide(e) {
    e.preventDefault();

    let index = this.state.activeIndex;
    let { slides } = this.props;
    let slidesLength = slides.length;

    if (index < 1) {
      index = slidesLength;
    }

    --index;

    this.setState({
      activeIndex: index
    });
  }

  goToNextSlide(e) {
    e.preventDefault();

    let index = this.state.activeIndex;
    let { slides } = this.props;
    let slidesLength = slides.length - 1;

    if (index === slidesLength) {
      index = -1;
    }

    ++index;

    this.setState({
      activeIndex: index
    });
  }

  render() {
    return (
      <div className="carousel">
        <a
          href="#"
          className="carousel__arrow carousel__arrow--left"
          onClick={e => this.goToPrevSlide(e)}
        >
          <span className="fa fa-2x fa-angle-left" />
        </a>

        <ul className="carousel__slides">
          {this.props.slides.map((slide, index) =>
            <li
              className={
                index == this.state.activeIndex
                  ? "carousel__slide carousel__slide--active"
                  : "carousel__slide"
              }
              key={index}
            >
              <p className="carousel-slide__content">{slide.content}</p>

              <p>
                <strong className="carousel-slide__author">
                  {slide.author}
                </strong>,
                {" "}<small className="carousel-slide__source">
                  {slide.source}
                </small>
              </p>
            </li>
          )}
        </ul>

        <a
          href="#"
          className="carousel__arrow carousel__arrow--right"
          onClick={e => this.goToNextSlide(e)}
        >
          <span className="fa fa-2x fa-angle-right" />
        </a>

        <ul className="carousel__indicators">
          {this.props.slides.map((slide, index) =>
            <li key={index}>
              <a
                className={
                  index == this.state.activeIndex
                    ? "carousel__indicator carousel__indicator--active"
                    : "carousel__indicator"
                }
                onClick={e => this.goToSlide(index)}
              />
            </li>
          )}
        </ul>
      </div>
    );
  }
}

// Render Carousel component
render(<Carousel slides={carouselSlidesData} />, carouselContainer);

Congratulations! You just built your own Carousel with React.js. I hope you enjoyed this tutorial and learned something or at least practiced what you already know. As I mentioned, I am still rather a beginner when it comes to React.js. So, if you find any mistake or way to improve the code, please share it in comment, tweet me or write a mail. Whatever you like. This will help improve this tutorial and make it more helpful.

I am still learning React and this was my first attempt to use it for creating a carousel. I know that there are many things that can be done better. I promise that I will get back to this tutorial in the next few days, review it and do my best to improve it. Then, I will publish updated version with code that follows the best practices. For now, please be lenient.

Thank you very much for your time. And, until next time, have a great day!

Did you like this article? Please subscribe.

Are you on social media? Let’s connect! You can find me on Twitter and Dribbble.

Originally published at Alex Devero Blog.