Building a React slider

Ryan Lucas
Ryan Lucas
Head of Design @ Retool

May 12, 2022

This post was written with help from Marie Starck.

In this article, you’ll learn how to build a slider in React with react-slider, a popular little component / library that Zillow open sourced back in 2021. We’ll cover how to customize the various components of the slider (dimensions, values, colors, etc.).

If you'd like to follow along on the completed project, you can see it in this GitHub repository.

Let’s dive in!

Implementing the Slider

Before we start writing code, let’s get our terms in order: sliders are composed of a track, a thumb, and if necessary, marks, indicated in the diagram below.

  • The track is the bar that represents the range of possible values, and is what the thumb moves on.
  • The thumb marks the current value of your slider. Its movement is restricted to the track.
  • The marks, sometimes also called ticks, represent various predefined values on your range. Each one can be clickable, which will move the thumb to its position.
  • track-0 and track-1 are specific to react-slider and are names for two CSS classes to select the part of the track before and after the thumb, respectively. These classes will be very helpful when styling your slider.

Installing React Slider

You'll need a React project to use with this tutorial. If you don't already have one, you can easily create one with Create-React-App:

1    npx create-react-app my-app
2

Then, in your project directory, install the react-slider library by running the following command:

1    npm install react-slider
2

To get things started, we’ll just render the default component. Inside your project, in src folder, create a file called Slider.js and add the component with your newly installed library:

1    import ReactSlider from "react-slider";
2    
3    const Slider = () => {
4      return (
5        <ReactSlider />
6      );
7    };ls 
8    
9    export default Slider;
10

Then, in App.js, import your new slider and add it to your application:

1import './App.css';
2import Slider from './Slider'
3
4function App() {
5  return (
6    <div className="App">
7      <Slider />
8    </div>
9  );
10}
11
12export default App;
13

Save both files and reload your application. Don't be alarmed when reloading results in a blank screen! If you open your dev tools, you'll see that the slider is there, just not yet visible:

This brings us to an important point about react-slider, which is that it’s not really an out-of-the-box solution. You can think of it like d3 – it’s more of a lower level framework that prioritizes customizability and power over ease of use (“just building a chart”). In its most basic form, it’s simply some div elements. To make them display in your app, you have to do some basic styling.

The following sections will walk you through the process of creating a simple slider.

Customizing the Track

There are two ways to customize your track:

  • renderTrack props: A custom render function that allows you to render the track portion of the slider. Essentially, it looks like: renderTrack={(props, state) => <div {...props} />}.
  • trackClassName Props: A CSS class for the track.

Using trackClassName is the easiest way to style your track. In your Slider component, simply add it to your slider along with a class for the whole slider:

1    import ReactSlider from "react-slider";
2    
3    const Slider = () => {
4      return (
5        <ReactSlider
6         className="customSlider"
7         trackClassName="customSlider-track"
8        />
9      );
10    };
11    
12    export default Slider;
13

Once the classes are set, you can write some CSS. If you are in a new React project, just head to your index.css file in your src folder.

Start by creating some global CSS variables for your colors. If you need to change things in the future, this will make it much easier, since you'll only have to change them in one place.

1    :root {
2      --main-color: rgb(104, 117, 217);
3      --main-color-hover: rgb(104, 117, 217, 0.2);
4      --track-color: #ddd;
5    }
6

In the same file, we’ll add some simple styling. Important properties to set are:

  • A max-width for your slider, in pixels
  • The height (or thickness) of the track, in pixels
  • A top value for the track. Without this, both the track and the thumb will be set to top: 0, which is the top of the div element. However, you want your track to be centered under the thumb. In order to do this, you need to lower the height of the track by setting a top value. The specific value depends on how big your thumb will be—bigger thumbs will need bigger values.
  • The color value of the track. This will have two parts: track-0 and track-1. The former is the part of the track before your thumb, while the latter is the default color of the track and is displayed after your thumb.

The end result will be something like this:

1    :root {
2      --main-color: rgb(104, 117, 217);
3      --main-color-hover: rgb(104, 117, 217, 0.2);
4      --track-color: #ddd;
5    }
6    
7    .customSlider {
8      /* max width of your slider */
9      max-width: 300px;
10      /* Optional: Only If you want to center your slider in the page */
11      margin: auto;
12    }
13    
14    .customSlider-track {
15      /* Top value to align your track to the center of your thumb */
16      top: 8px;
17      /* thickness of the track */
18      height: 4px;
19     /* default color of your track */
20      background: var(--track-color);
21    }
22    
23    .customSlider-track.customSlider-track-0 {
24      /* color of the track before the thumb */
25      background: var(--main-color);
26    }
27

After refreshing your browser, you'll see this:

Your track is now visible, and technically, you can select a value. It’s not very practical without a thumb, though, so let’s make one.

Customizing thee Thumb

Going back to Slider.js, add a class for your custom thumb using thumbClassName:

1    import ReactSlider from "react-slider";
2    
3    const Slider = () => {
4      return (
5        <ReactSlider
6         className="customSlider"
7         trackClassName="customSlider-track"
8         thumbClassName="customSlider-thumb"
9        />
10      );
11    };
12    
13    export default Slider;
14

Then, for your styling, create the class customSlider-thumb in your CSS file. Remember that the slider is ultimately a list of div elements. This means that you'll need a few things:

  • A cursor pointer, so that the user knows there is an interaction available (clicking or dragging).
  • A shape for your thumb. This can be anything you want, but for this tutorial, weyou'll make it a circle. In CSS, you do so by making a square, and then using border-radius to round the edges into a circle.
  • A color for your thumb. As with the track, background is used to color your element.

In the end, you should have something similar to this:

1    .customSlider-thumb {
2      cursor: pointer;
3      /*color for the thumb */
4      background: var(--main-color);
5      /* shape of the thumb: circle */
6      width: 20px;
7      height: 20px;
8      border-radius: 100%;
9      /* remove default outline when selected */
10      outline: none;
11    }
12    
13    .customSlider-thumb:hover {
14      box-shadow: 0 0 0 8px var(--main-color-hover);
15    }
16

In this styling, an outline:none rule was added so as to not have a default border when the thumb is selected.

This example also adds some custom styling when the user hovers the thumb. This particular box-shadow styling mimics Material UI slider styling.

If you refresh, you should now be able to see the thumb:

Customizinge Marks

At this point, you have a styled track and thumb. But what about marks?

As with the track, you can simply pass a custom class to markClassName, then addcreate some CSS styling to make them appear.

In your Slider component, there are a couple of interesting props you canwill use to set your marks:

  • min: The minimum value of your slider. Defaults to 0.
  • max: The maximum value of your slider. Defaults to 100.
  • marks: The marks that will appear. There are several ways to set this:
    • Pass an array of values, which means that only those values will appear.
    • Pass a single number to indicate an increment; eg if you pass 5, there will be marks at five, ten, fifteen, and so on.
    • Set the value to true, which will cause all marks to appear.
  • markClassName: CSS class name for the marks.

We’ll start by setting some basic values for each of these:

1    <ReactSlider
2          className="customSlider"
3          thumbClassName="customSlider-thumb"
4          trackClassName="customSlider-track"
5          markClassName="customSlider-mark"
6          marks={20}
7          min={0}
8          max={100}
9    />
10

In your CSS file, add some styling to make those marks more prominent:

1    :root {
2      --main-color: rgb(104, 117, 217);
3      --main-color-hover: rgb(104, 117, 217, 0.2);
4      --track-color: #ddd;
5    /* Default mark color*/
6      --mark-color: #aaaaaa;
7    }
8       ...
9    .customSlider-mark {
10      cursor: pointer;
11      top: 6px;
12      width: 1.5px;
13      height: 8px;
14      background-color: var(--mark-color);
15    }
16

If you refresh your browser, you should now see the marks:

There are more ways to customize the marks. For example, they could be the same color as the track.

To do this, go back to your Slider component. Inside, you'll import the useState React hook to create a currentValue variable to keep track of your slider’s value. The React Slider library also offers props for defaultValue, value, and onChange, which you might already be familiar with.

1    import { useState } from "react";
2    ...
3    const Slider = () => {
4      const [currentValue, setCurrentValue] = useState(0);
5      
6      return (
7          <ReactSlider
8           ...
9            defaultValue={0}
10            value={currentValue}
11            onChange={(value) => setCurrentValue(value)}
12          />
13      );
14    };
15

There's also a renderMark prop. This provides a custom render function for your mark. In this function, we will have a class name that changes depending on if the mark’s value, or the key, is greater than, less than, or equal to the slider’s current value.

1    <ReactSlider
2      ....
3      renderMark={(props) => {
4         if (props.key < currentValue) {
5            props.className = "customSlider-mark customSlider-mark-before";
6          } else if (props.key === currentValue) {
7           props.className = "customSlider-mark customSlider-mark-active";
8         }
9         return <span {...props} />;
10      }}
11    />
12

The Slider.js file to this point will look like this:

1    import { useState } from "react";
2    import ReactSlider from "react-slider";
3    
4    const Slider = () => {
5      const [currentValue, setCurrentValue] = useState(0);
6    
7      return (
8        <ReactSlider
9          className="customSlider"
10          thumbClassName="customSlider-thumb"
11          trackClassName="customSlider-track"
12          markClassName="customSlider-mark"
13          marks={20}
14          min={0}
15          max={100}
16          defaultValue={0}
17          value={currentValue}
18          onChange={(value) => setCurrentValue(value)}
19          renderMark={(props) => {
20             if (props.key < currentValue) {
21               props.className = "customSlider-mark customSlider-mark-before";
22             } else if (props.key === currentValue) {
23               props.className = "customSlider-mark customSlider-mark-active";
24             }
25             return <span {...props} />;
26          }}
27        />
28      );
29    };
30    
31    export default Slider;
32

You'll also need some CSS for your customSlider-mark-before and customSlider-mark-active classes. Inside your CSS file, add the final styles needed to complete your slider:

1    .customSlider-mark.customSlider-mark-before {
2      background-color: var(--main-color);
3    }
4    
5    .customSlider-mark.customSlider-mark-active {
6      display: none;
7    }
8

This will make the marks the same color as the track if they appear before the thumb, and disappear if they're under the thumb.

The result should look like this:

If you'd like to see the whole project in one place, you can do so at this GitHub repository.

Reader

Ryan Lucas
Ryan Lucas
Head of Design @ Retool
May 12, 2022
Copied