Hooks for building range and multi-range sliders in React
react-ranger
Hooks for building range and multi-range sliders in React.
Quick Features
- Headless!
- Single or Multiple Handles
- Handle Devider Items
- Custom Steps or Step-Size
- Custom Ticks
Examples
- Basic - CodeSandbox - Source
- Multi-Range - CodeSandbox - Source
- Custom Steps - CodeSandbox - Source
- Custom Styles - CodeSandbox - Source
- Update On Drag - CodeSandbox - Source
Installation
$ npm i --save react-ranger
# or
$ yarn add react-ranger
Sample Usage
The following is a very basic example of a single range input that looks similar to Chrome's default appearance.
import ReactRanger from 'react-ranger'
function App() {
  const [values, setValues] = React.useState([10])
  const { getTrackProps, handles } = useRanger({
    values,
    onChange: setValues,
    min: 0,
    max: 100,
    stepSize: 5,
  })
  return (
    <>
      <div
        {...getTrackProps({
          style: {
            height: '4px',
            background: '#ddd',
            boxShadow: 'inset 0 1px 2px rgba(0,0,0,.6)',
            borderRadius: '2px',
          },
        })}
      >
        {handles.map(({ getHandleProps }) => (
          <div
            {...getHandleProps({
              style: {
                width: '12px',
                height: '12px',
                borderRadius: '100%',
                background: 'linear-gradient(to bottom, #eee 45%, #ddd 55%)',
                border: 'solid 1px #888',
              },
            })}
          />
        ))}
      </div>
    </>
  )
}
Options
- value: Array<number>- The current value (or values) for the range- Required
 
- min: number- The minimum limit for the range- Required
 
- max: number- The maximum limit for the range- Required
 
- stepSize: number- The distance between selectable steps- Required
 
- steps: arrayOf(number)- An array of custom steps to use. This will override- stepSize,
- tickSize: number
- ticks: arrayOf(number): Default: 10- An array of custom ticks to use. This will override- tickSize,
- onChange: Function(newValue)- A function that is called when the handle is released
- onDrag: Function(newValue)- A function that is called when a handled is dragged
- interpolator: { getPercentageForValue: Function(value) => decimal, getValueForClientX: Function(x) => value}- The Interpolator to use
- Defualts to the bundled linear-scale interpolator
 See the Interpolation section for more info
 
Returns
useRanger returns an object with the following properties:
- getTrackProps(userProps): func- A function that takes optional props and returns the combined necessary props for the track component.
- ticks: array- Ticks to be rendered. Each- tickhas the following props:- value: number- The tick number to be displayed
- getTickProps(userProps): func- A function that take optional props and returns the combined necessary props for the tick component.
 
- segments: array- Segments to be rendered. Each- segmenthas the following props:- value: number- The segments ending value
- getSegmentProps(userProps): func- A function that take optional props and returns the combined necessary props for the segment component.
 
- handles: array- Handles to be rendered. Each- handlehas the following props:- value: number- The current value for the handle
- active: boolean- Denotes if the handle is currently being dragged.
- getHandleProps(userProps): func- A function that take optional props and returns the combined necessary props for the handle component.
 
- activeHandleIndex: oneOfType([null, number])- The zero-based index of the handle that is currently being dragged, or- nullif no handle is being dragged.
Interpolation
By default, react-ranger uses linear interpolation between data points, but allows you to easily customize it to use your own interpolation functions by passing an object that implements the following interface:
const interpolator = {
  // Takes the value & range and returns a percentage [0, 100] where the value sits from left to right
  getPercentageForValue: (val: number, min: number, max: number): number
  // Takes the clientX (offset from the left edge of the ranger) along with the dimensions
  // and range settings and transforms a pixel coordinate back into a value
  getValueForClientX: (clientX: number, trackDims: object, min: number, max: number): number
}
Here is an exmaple of building and using a logarithmic interpolator!
import { useRanger } from 'react-ranger'
const logInterpolator = {
  getPercentageForValue: (val, min, max) => {
    const minSign = Math.sign(min)
    const maxSign = Math.sign(max)
    if (minSign !== maxSign) {
      throw new Error(
        'Error: logarithmic interpolation does not support ranges that cross 0.'
      )
    }
    let percent =
      (100 / (Math.log10(Math.abs(max)) - Math.log10(Math.abs(min)))) *
      (Math.log10(Math.abs(val)) - Math.log10(Math.abs(min)))
    if (minSign < 0) {
      // negative range, means we need to invert our percent because of the Math.abs above
      return 100 - percent
    }
    return percent
  },
  getValueForClientX: (clientX, trackDims, min, max) => {
    const { left, width } = trackDims
    let value = clientX - left
    value *= Math.log10(max) - Math.log10(min)
    value /= width
    value = Math.pow(10, Math.log10(min) + value)
    return value
  },
}
useRanger({
  interpolator: logInterpolator,
})