[React + styled-componenets] 커스텀 range slider 만들기

2023. 10. 23. 00:50
반응형

 

사이드 프로젝트 진행 중, 위와같이 드래그해서 value를 설정할 수 있는 슬라이더가 필요했다.

npm에 마땅한 게 없어서 직접 만들어 구현하기로 했다.

 

RangeSlider.tsx

import { useState } from 'react'
import styled from 'styled-components'

const Slider = styled.input`
  position: absolute;
  top: 50%;
  width: 100%;
  height: 12px;
  -webkit-appearance: none;
  background: transparent;
  margin: 0;
  border: 0;

  &:active {
    cursor: grabbing;
  }

  &:focus {
    outline: none;
  }
`

const SliderContainer = styled.div`
  width: 328px;
  height: 42px;
  margin: 0 auto;
  position: relative;

  ::-webkit-slider-thumb {
    -webkit-appearance: none;
    background: ${({ theme }) => theme.colors.green};
    width: 42px;
    height: 42px;
    border-radius: 50%;
  }
`

const SliderRail = styled.div`
  width: 100%;
  height: 12px;
  border-radius: 2px;
  background-color: ${({ theme }) => theme.colors.gray};
  position: absolute;
  top: 50%;
`

const SliderFillTrack = styled.div<{ fill: string }>`
  width: ${(props) => props.fill};
  height: 12px;
  border-radius: 2px;
  background-color: blue;
  position: absolute;
  top: 50%;
`

type Props = {
  value: number
  min?: number
  max?: number
  step?: number
  onChange: (e: React.ChangeEvent<HTMLInputElement>) => void
}

const RangeSlider = ({ value, min, max, step, onChange }: Props) => {
  const [currentValue, setCurrentValue] = useState<number>(value)

  return (
    <SliderContainer>
      <SliderRail />
      <SliderFillTrack fill={`${(currentValue / (max - min)) * 100}%`} />
      <Slider
        type="range"
        defaultValue={value}
        min={min}
        max={max}
        step={step}
        onChange={onChange}
      />
    </SliderContainer>
  )
}

export default RangeSlider

 

 

위 슬라이더를 import 해서 쓰는 컴포넌트

const AddComment = () => {

  const [value, setValue] = useState<number>(0)

  const handleSliderChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setValue(Number(event.target.value))
  }

  return (
    <>
      <SliderContainer>
        <div className="title">
          <Typo fontSet="subBold17" color="green">
            {ReadingStatusMap[value]}
          </Typo>
        </div>
        <div className="bar">
          <RangeSlider value={value} step={1} min={0} max={4} onChange={handleSliderChange} />
        </div>
      </SliderContainer>
    </>
  )
}
export default AddComment
반응형

BELATED ARTICLES

more