ReactHustle

Create a React Multi Range Slider with two Handles using react-slider and TailwindCSS

Jasser Mark Arioste

Jasser Mark Arioste

Create a React Multi Range Slider with two Handles using react-slider and TailwindCSS

Hello, hustlers! In this tutorial,  you'll learn how to create a react multi-range slider step-by-step by using the react-slider package. We'll also use Tailwind CSS classes for the styling and the classnames package to control the styles. Also, I use Typescript for all my projects so we'll be using it as well.

What is the react-slider package? #

The react-slider package is a very small (3.9kB min+gzipped) and versatile component library to implement range sliders. It is completely unstyled, so it's up to you to implement the styling depending on the component state. We can implement regular, multi-range sliders with vertical or horizontal orientations. 

It also has a minimal footprint (only 3.9kB) and no dependencies.

Why use TailwindCSS? #

I really like to use TailwindCSS since it's very flexible a set of CSS utility classes. It's very easy to integrate CSS utility classes into any component library in React.

Final Output #

Here's the final output of the react multi-range slider that we'll be making today.

React range-slider final output

Things to Do #

  1. Project setup. We'll set up a NextJS Typescript project + TailwindCSS Setup for this tutorial.
  2. Create a wrapper component for ReactSlider that uses typescript and our styles.
  3. Style the slider Thumb using TailwindCSS. The Thumb is the handle that has the current slider value.
  4. Style the slider Tracks. Tracks are the light gray and indigo lines you see above. We must consider that sometimes there are 2 values (for multi-range). We'll have to style it accordingly.
  5. Style the slider Marks/Steps. The marks/steps are the tiny dots representing each slider step.
  6. Style the Thumb according to horizontal/vertical orientation.

Step 0 - Project Setup #

If you already have Tailwind CSS installed on your project, you may skip this step. If you're using a different framework other than NextJS, please check tailwind CSS installation docs.

To follow along on this tutorial, I created a NextJS starter template in GitHub that has Tailwind CSS pre-installed so we'll just use that to bootstrap our project. Run the following command:

npx create-next-app -e https://github.com/jmarioste/react-multi-range-slider-tutorial react-multi-range-slider

Next, run the following command to start the local server:

cd react-multi-range-slider && yarn dev

Go to localhost:3000 and you'll be greeted by this screen:

React multi-range slider tutorial home page

Step 1 - Installing the Dependencies #

Now that the setup is done, let's install all the dependencies we'll be using. Run the following command:

yarn add react-slider classnames && yarn add -D @types/react-slider

Step 2 - Creating the Wrapper Component #

Next, let's create a wrapper component called RangeSlider.  Create the file components/RangeSlider.ts and copy the code below:

// components/RangeSlider.tsx
import React from "react";
import ReactSlider, { ReactSliderProps } from "react-slider";
const RangeSlider = <T extends number | readonly number[]>(_props: ReactSliderProps<T>) => {
  return <ReactSlider {..._props} className="w-full h-full" />;
};
export default RangeSlider;
1234567

Explanation:

Line 3-4: To properly create a wrapper component, we use the ReactSliderProps so that we can just use whatever props it already has. But since ReactSliderProps  has a generic parameter <T> that accepts number or number[], we have to convert our component into a generic component as well.

If we don't use a generic component, you'll get an error when assigning a value of type number[] in values or defaultValues prop. For example, let's say we define our component like this:

// components/ReactSliderNonGeneric.tsx
import React from "react";
import ReactSlider, { ReactSliderProps } from "react-slider";
const RangeSliderNonGeneric = (_props: ReactSliderProps) => {
  return <ReactSlider {..._props} className="w-full h-full" />;
};
export default RangeSliderNonGeneric;

1234567

We'll get a compile-time error: Type 'number[]' is not assignable to type 'number'. when using the component.

React-slider: Type 'number[]' is not assignable to type 'number'.

Step 3 - Styling the Thumb Component #

The next step is to style the Thumb component. We'll use the renderThumb prop to fully customize how we render our thumb component. The renderThumb prop is a custom render function for dynamic thumb content:

// components/RangeSlider.tsx
import React from "react";
import ReactSlider, { ReactSliderProps } from "react-slider";
import cn from "classnames";
const RangeSlider = <T extends number | readonly number[]>(
  _props: ReactSliderProps<T>
) => {
  const isVertical = _props.orientation === "vertical";
  return (
    <ReactSlider
      {..._props}
      renderThumb={(props, state) => (
        <div
          {...props}
          className={cn({
            "h-full": !isVertical,
            "w-full": isVertical,
            "aspect-square rounded-full bg-indigo-500 text-xs text-white flex items-center justify-center cursor-grab":
              true,
          })}
        >
          {state.valueNow}
        </div>
      )}
    />
  );
};
export default RangeSlider;
12345678910111213141516171819202122232425262728

Explanation:

Line 4: We import classnames to easily control the classes

Line 8: We check if the orientation is vertical or horizontal.

Line 13-25: We implement the thumb content. We consider the orientation and adjust the styling accordingly. We use apsect-square and rounded-full classes to make sure it's a circle depending on the height or width of the slider.

To use it we can just add classes to define the dimensions:

import type { NextPage } from "next";
import RangeSlider from "../components/RangeSlider";
const Home: NextPage = () => {
  return (
    <div className="flex flex-col gap-2 p-4">
      <h1 className="text-3xl font-bold underline">Hello world!</h1>
      <RangeSlider className="w-80 h-12" defaultValue={50} />
      <RangeSlider className="w-40 h-8" defaultValue={[25, 75]} />
      <RangeSlider
        className="w-8 h-40"
        orientation="vertical"
        defaultValue={50}
      />
    </div>
  );
};
export default Home;


1234567891011121314151617

After this step, we can already play with our range slider a bit:

React multi-range slider demo after thumb styling

Step 4 - Styling the Tracks #

The next step is to style the tracks. There will be more logic in this step since we have to consider the number of values as well as the orientation. We'll use the renderTrack prop which is similar to the renderThumb prop.

// components/RangeSlider.tsx
import React from "react";
import ReactSlider, { ReactSliderProps } from "react-slider";
import cn from "classnames";
const RangeSlider = <T extends number | readonly number[]>(
  _props: ReactSliderProps<T>
) => {
  const isVertical = _props.orientation === "vertical";
  return (
    <ReactSlider
      {..._props}
      ...
      renderTrack={(props, state) => {
        //check if there are multiple values
        const points = Array.isArray(state.value) ? state.value.length : null;
        const isMulti = points && points > 0;
        const isLast = isMulti ? state.index === points : state.index === 1;
        const isFirst = state.index === 0;
        return (
          <div
            {...props}
            className={cn({
              //use 1/4 height or width depending on the orientation and make sure to center it.
              "h-1/4 top-1/2 -translate-y-1/2": !isVertical,
              "w-1/4 left-1/2 -translate-x-1/2": isVertical,
              "rounded-full": true,
              "bg-gray-200": isMulti ? isFirst || isLast : isLast,
              "bg-indigo-500": isMulti ? !isFirst || !isLast : isFirst,
            })}
          ></div>
        );
      }}
    />
  );
};
export default RangeSlider;
123456789101112131415161718192021222324252627282930313233343536

Explanation:

react-slider provides state.index the position of the track relative to the value.  We change the background color depending on the index/position of the track.

After this step, here's the output:

React mutli-range slider after step 3

It already looks good and usable. 

Step 4 (Optional) - Styling the Steps/Marks #

This step is optional if you don't want to style it. We'll use the renderMark prop similar to the previous two render functions:

// components/RangeSlider.tsx
import React from "react";
import ReactSlider, { ReactSliderProps } from "react-slider";
import cn from "classnames";
const RangeSlider = <T extends number | readonly number[]>(
  _props: ReactSliderProps<T>
) => {
  const isVertical = _props.orientation === "vertical";
  return (
    <ReactSlider
      {..._props}
      ... 
      renderMark={(props) => {
        return (
          <div
            {...props}
            className={cn({
              "top-1/2 -translate-y-1/2": !isVertical,
              "left-1/2 -translate-x-1/2": isVertical,
              "w-1/5 h-1/5": true,
              "rounded-full bg-indigo-500": true,
            })}
          ></div>
        );
      }}
    />
  );
};
export default RangeSlider;
1234567891011121314151617181920212223242526272829

Usage:

// pages/index.tsx
import type { NextPage } from "next";
import RangeSlider from "../components/RangeSlider";
const Home: NextPage = () => {
  return (
    <div className="flex flex-col gap-2 p-4">
      <RangeSlider
        className="w-80 h-12"
        defaultValue={50}
        marks={10}
        step={10}
      />
      <RangeSlider className="w-40 h-8" defaultValue={[25, 75]} />
      <RangeSlider
        className="w-8 h-40"
        orientation="vertical"
        defaultValue={50}
      />
    </div>
  );
};
export default Home;
12345678910111213141516171819202122

That's it!

Full Code and Demo #

The full code is available at GitHub step-by-step-tutorial branch.

The demo is available on Stackblitz: React Multi-Range Slider Demo 

Conclusion #

We learned how to create a react multi-range slider by using the awesome package react-slider that already has this functionality and we only needed to add the styling. We used Tailwind CSS to easily style the individual components of the slider.

If you like this tutorial, please leave a like or share this article. For future tutorials like this, please subscribe to our newsletter.

Credits: Image by Alex Hu from Pixabay

Share this post!

Related Posts

Disclaimer

This content may contain links to products, software and services. Please assume all such links are affiliate links which may result in my earning commissions and fees.
As an Amazon Associate, I earn from qualifying purchases. This means that whenever you buy a product on Amazon from a link on our site, we receive a small percentage of its price at no extra cost to you. This helps us continue to provide valuable content and reviews to you. Thank you for your support!
Donate to ReactHustle