Search code examples
javascripthtmlcssreactjsmaterial-ui

Material-UI - Thumbs switching style in range Slider


I have two entities to show as a thumb component on Material-UI Slider and I need different styling for each thumb component.

Entity A thumb should appear in white circle and Entity B thumb should appear in Red circle. I partially achieved this functionality by using data index

if (data-index === 0) {

//show white circle
} else {
//show red circle
}

However there is one big flaw in this i.e. if I slide entity B and make it stand before entity A then entity B changes to white circle because data-index of entity B becomes 0. Is there any other approach than using data-index where I can maintain the styling irrespective of where they stand on slider.

Here is the sandbox.

import * as React from "react";
import PropTypes from "prop-types";
import Slider, { SliderThumb } from "@material-ui/core/Slider";
import { styled } from "@material-ui/core/styles";
import Typography from "@material-ui/core/Typography";
import Box from "@material-ui/core/Box";
import clsx from "clsx";

const EntitySlider = styled(Slider)(({ theme }) => ({
  color: "#3a8589",
  height: 3,
  padding: "13px 0",
  "& .MuiSlider-thumb": {
    height: 27,
    width: 27,
    backgroundColor: "#fff",
    border: "1px solid currentColor",
    "&.second-thumb": {
      backgroundColor: "red"
    },
    "&:hover": {
      boxShadow: "0 0 0 8px rgba(58, 133, 137, 0.16)"
    }
  },
  "& .MuiSlider-track": {
    height: 3
  },
  "& .MuiSlider-rail": {
    color: theme.palette.mode === "dark" ? "#bfbfbf" : "#d8d8d8",
    opacity: theme.palette.mode === "dark" ? undefined : 1,
    height: 3
  }
}));

function ThumbComponent(props) {
  const { children, className, ...other } = props;
  const extraClassName =
    other["data-index"] === 0 ? "first-thumb" : "second-thumb";
  return (
    <SliderThumb {...other} className={clsx(className, extraClassName)}>
      {children}
    </SliderThumb>
  );
}

ThumbComponent.propTypes = {
  children: PropTypes.node
};

export default function CustomizedSlider() {
  return (
    <Box sx={{ width: 320 }}>
      <Typography gutterBottom>Airbnb</Typography>
      <EntitySlider
        components={{ Thumb: ThumbComponent }}
        getAriaLabel={(index) =>
          index === 0 ? "Minimum price" : "Maximum price"
        }
        defaultValue={[20, 40]}
      />
    </Box>
  );
}


Solution

  • Is there any other approach than using data-index where I can maintain the styling irrespective of where they stand on slider

    Your styling works as expected, the only unexpected thing is that when you drag the white thumb pass the red thumb, the red thumb starts getting dragged and the white thumb stops because MUI Slider doesn't allow the left thumb to move pass the right thumb. You can see from the source code that the value array always gets sorted, and Slider will find the closest thumb index from the current value to set as active:

    {/* white thumb on the left, red thumb on the right */}
    <Slider value={[0, 100]} {...} />
    {/* white thumb still on the left, red thumb still on the right */}
    <Slider value={[100, 0]} {...} />
    

    So yes, the styling of the thumb is consistent, it's just that the thumb position is restricted between the other thumbs and the min/max value.

    Reference