{"id":13683254,"url":"https://github.com/tajo/react-range","last_synced_at":"2025-05-14T16:12:29.590Z","repository":{"id":34081578,"uuid":"169130885","full_name":"tajo/react-range","owner":"tajo","description":"🎚️Range input with a slider. Accessible. Bring your own styles and markup.","archived":false,"fork":false,"pushed_at":"2024-08-07T06:54:22.000Z","size":2800,"stargazers_count":875,"open_issues_count":19,"forks_count":99,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-04-11T05:13:41.856Z","etag":null,"topics":["component","draggable","range","react","slider"],"latest_commit_sha":null,"homepage":"https://react-range.pages.dev","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tajo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-02-04T18:57:38.000Z","updated_at":"2025-04-06T17:13:15.000Z","dependencies_parsed_at":"2024-12-19T00:01:24.949Z","dependency_job_id":"0d97d031-8d4e-4a0a-9ea1-3973faa18392","html_url":"https://github.com/tajo/react-range","commit_stats":{"total_commits":241,"total_committers":43,"mean_commits":5.604651162790698,"dds":0.5684647302904564,"last_synced_commit":"e13a6adcfb7be7f6a9ddc7c006244bfa0dc2fea3"},"previous_names":[],"tags_count":59,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tajo%2Freact-range","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tajo%2Freact-range/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tajo%2Freact-range/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tajo%2Freact-range/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tajo","download_url":"https://codeload.github.com/tajo/react-range/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248345268,"owners_count":21088245,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["component","draggable","range","react","slider"],"created_at":"2024-08-02T13:02:05.467Z","updated_at":"2025-04-11T05:13:46.635Z","avatar_url":"https://github.com/tajo.png","language":"TypeScript","funding_links":[],"categories":["TypeScript","React"],"sub_categories":["React Components"],"readme":"# react-range\n\n[![npm version](https://img.shields.io/npm/v/react-range.svg?style=flat-square)](https://www.npmjs.com/package/react-range)\n[![npm downloads](https://img.shields.io/npm/dm/react-range.svg?style=flat-square)](https://www.npmjs.com/package/react-range)\n[![size](https://img.shields.io/bundlephobia/minzip/react-range.svg?style=flat)](https://bundlephobia.com/result?p=react-range)\n\u003ca href=\"https://stackblitz.com/edit/react-range-edit?file=src%2FApp.tsx\"\u003e\u003cimg src=\"https://img.shields.io/badge/stackblitz-sandbox-orange\" alt=\"stackblitz\"\u003e\u003c/a\u003e\n\n![Labeled Range](https://raw.githubusercontent.com/tajo/react-range/main/assets/react-range.gif?raw=true)\n\n[See all the other examples](https://react-range.pages.dev) and [their source code](https://github.com/tajo/react-range/tree/main/examples)! Try it out in the [Stackblitz sandbox](https://stackblitz.com/edit/react-range-edit?file=src%2FApp.tsx)!\n\n## Installation\n\n```\npnpm add react-range\n```\n\n## Usage\n\n```jsx\nimport * as React from \"react\";\nimport { Range } from \"react-range\";\n\nconst SuperSimple: React.FC = () =\u003e {\n  const [values, setValues] = React.useState([50]);\n  return (\n    \u003cRange\n      label=\"Select your value\"\n      step={0.1}\n      min={0}\n      max={100}\n      values={values}\n      onChange={(values) =\u003e setValues(values)}\n      renderTrack={({ props, children }) =\u003e (\n        \u003cdiv\n          {...props}\n          style={{\n            ...props.style,\n            height: \"6px\",\n            width: \"100%\",\n            backgroundColor: \"#ccc\",\n          }}\n        \u003e\n          {children}\n        \u003c/div\u003e\n      )}\n      renderThumb={({ props }) =\u003e (\n        \u003cdiv\n          {...props}\n          key={props.key}\n          style={{\n            ...props.style,\n            height: \"42px\",\n            width: \"42px\",\n            backgroundColor: \"#999\",\n          }}\n        /\u003e\n      )}\n    /\u003e\n  );\n};\n```\n\n## Features\n\n- Range input supporting **vertical and horizontal sliding**\n- Unopinionated styling, great for **CSS in JS** too\n- No wrapping divs or additional markup, bring your own!\n- Works with keyboard, uses `aria` patterns for assistive technologies, check a11y part for accessibility info\n- **Touchable**, works on mobile devices\n- Can handle negative and decimal values\n- Stateless and controlled single component\n- **No dependencies, 6kB (gzipped)**\n- Coverage by [e2e playwright tests](#end-to-end-testing)\n- RTL support\n\n\n\n## A11y (accessibility)\n\n### Keyboard support\n\n- `tab` and `shift+tab` to focus thumbs\n- `arrow up` or `arrow right` or `k` to increase the thumb value by one step\n- `arrow down` or `arrow left` or `j` to decrease the thumb value by one step\n- `page up` to increase the thumb value by ten steps\n- `page down` to decrease the thumb value by ten steps\n\n### Assistive technologies (for example screen readers)\n\n*You are responsible for the accessibility name!*\n\nDefault accessibility name is Accessibility label, set with code: `aria-label=\"Accessibility label\"`, but is not visible (only for screen-readers and other assistive tech), \nso make sure to use correct name by passing it to the prop called `label`.\n\nIf you want to have a visible label (best practice), then use `labelledBy`.\n\nYou naming options are:\n\n- you can name it by using `label` prop (translates to `aria-label` in the code)\n- you can name it by adding a visual element with a unique ID that can be used with `labelledBy` prop (translates to `aria-labellebdy` in the code)\n\nPlease check `Basic` and `Basic visible label` examples for more info.\n\nAria used on the component is following [Accessible Rich Internet Applications (WAI-ARIA) 1.2 `slider` role](https://www.w3.org/TR/wai-aria-1.2/#slider), but please be aware that different assistive technologies provide different support (especially in combination with operating systems and browsers).\n\nTherefore please make sure to test it yourself and with people with disabilities.\nWe can not provide prompt information about support, but are happy to add your findings to this Readme.\n\n### Conformance to WCAG and other accessibility standards\n\nWe need to do more testing to claim any conformance. We did make sure the component is operable with keyboard, that it is respecting ARIA patterns for `slider` role and having possibility to name the component (accessible name). You are welcome to report any accessibility related findings, we look forward to add information about user tests and support for assistive technologies.\n\n## `\u003cRange /\u003e` props\n\n### renderTrack\n\n```ts\nrenderTrack: (params: {\n  props: {\n    style: React.CSSProperties;\n    ref: React.RefObject\u003cany\u003e;\n    onMouseDown: (e: React.MouseEvent) =\u003e void;\n    onTouchStart: (e: React.TouchEvent) =\u003e void;\n  };\n  children: React.ReactNode;\n  isDragged: boolean;\n  disabled: boolean;\n}) =\u003e React.ReactNode;\n```\n\n`renderTrack` prop to define your track (root) element. **Your function gets four parameters and should return a React component**:\n\n- `props` - this needs to be spread over the root track element, it connects mouse and touch events, adds a ref and some necessary styling\n- `children` - the rendered thumbs, thumb structure should be specified in a different prop - `renderThumb`\n- `isDragged` - `true` if any thumb is being dragged\n- `disabled` - `true` if `\u003cRange disabled={true} /\u003e` is set\n\nThe track can be a single narrow `div` as in the [Super simple example](https://github.com/tajo/react-range/blob/main/examples/SuperSimple.tsx); however, it might be better to use at least two nested `div`s where the outer `div` is much thicker and has a transparent background and the inner `div` is narrow, has visible background and is centered. `props` should be then spread over the outer bigger `div`. **Why to do this? It's nice to keep the `onMouseDown` and `onTouchStart` targets bigger** since the thumb can be moved also by clicking on the track (in a single thumb scenario).\n\n### renderThumb\n\n```ts\nrenderThumb: (params: {\n  props: {\n    key: number;\n    style: React.CSSProperties;\n    tabIndex?: number;\n    \"aria-valuemax\": number;\n    \"aria-valuemin\": number;\n    \"aria-valuenow\": number;\n    draggable: boolean;\n    role: string;\n    onKeyDown: (e: React.KeyboardEvent) =\u003e void;\n    onKeyUp: (e: React.KeyboardEvent) =\u003e void;\n  };\n  value: number;\n  index: number;\n  isDragged: boolean;\n}) =\u003e React.ReactNode;\n```\n\n`renderThumb` prop to define your thumb. **Your function gets four parameters and should return a React component**:\n\n- `props` - it has multiple props that you need to spread over your thumb element\n- `value` - a number, relative value based on `min`, `max`, `step` and the thumb's position\n- `index` - the thumb index (order)\n- `isDragged` - `true` if the thumb is dragged, great for styling purposes\n\n### renderMark (optional)\n\n```ts\nrenderMark?: (params: {\n  props: {\n    key: string;\n    style: React.CSSProperties;\n    ref: React.RefObject\u003cany\u003e;\n  };\n  index: number;\n}) =\u003e React.ReactNode;\n```\n\n`renderMark` is an optional prop so you can render an element at each step. See this [example](https://react-range.pages.dev/?story=range--marks). **Your function gets 2 parameters and should return a React component**:\n\n- `props` - this needs to be spread over the root track element, it adds a ref, key and some necessary styling\n- `index` - index of the mark, might be useful if you want to use different styles for even/odd marks\n\nYou can use any dimensions for your marks and react-range will automatically position them at the correct place.\n\n### values\n\n```ts\nvalues: number[];\n```\n\nAn array of numbers. It controls the position of thumbs on the track. `values.length` equals to the number of rendered thumbs.\n\n### onChange\n\n```ts\nonChange: (values: number[]) =\u003e void;\n```\n\nCalled when a thumb is moved, provides new `values`.\n\n### onFinalChange\n\n```ts\nonFinalChange: (values: number[]) =\u003e void;\n```\n\nCalled when a change is finished (mouse/touch up, or keyup), provides current `values`. Use this event when you have to make for example ajax request with new values.\n\n### min (optional)\n\n```ts\nmin: number;\n```\n\nThe range start. Can be decimal or negative. Default is `0`.\n\n### max (optional)\n\n```ts\nmax: number;\n```\n\nThe range end. Can be decimal or negative. Default is `100`.\n\n### step (optional)\n\n```ts\nstep: number;\n```\n\nThe minimal distance between two `values`. Can be decimal. Default is `1`.\n\n### allowOverlap (optional)\n\n```ts\nallowOverlap: boolean;\n```\n\nWhen there are multiple thumbs on a single track, should they be allowed to overlap? Default is `false`.\n\n### draggableTrack (optional)\n\n```ts\ndraggableTrack: boolean;\n```\n\nWhen there are multiple thumbs on a single track, should it be possible to drag all thumbs at once? Default is `false`.\n\n### direction (optional)\n\n```ts\ndirection: Direction;\n\nenum Direction {\n  Right = \"to right\",\n  Left = \"to left\",\n  Down = \"to bottom\",\n  Up = \"to top\",\n}\n```\n\nIt sets the orientation (vertical vs horizontal) and the direction in which the value increases. You can get this enum by:\n\n```js\nimport { Direction } from \"react-range\";\n```\n\nDefault value is `Direction.Right`.\n\n### disabled (optional)\n\n```ts\ndisabled: boolean;\n```\n\nIf `true`, it ignores all touch and mouse events and makes the component not focusable. Default is `false`.\n\n### rtl (optional)\n\n```ts\nrtl: boolean;\n```\n\nIf `true`, the slider will be optimized for RTL layouts. Default is `false`.\n\n## getTrackBackground\n\nThere is an additional helper function being exported from `react-range`. Your track is most likely a `div` with some background. What if you want to achieve a nice \"progress bar\" effect where the part before the thumb has different color than the part after? What if you want to have the same thing even with multiple thumbs (aka differently colored segments)? **You don't need to glue together multiple divs in order to do that!** You can use a single `div` and set `background: linear-gradient(...)`. `getTrackBackground` function builds this verbose `linear-gradient(...)` for you!\n\n```ts\ngetTrackBackground: (params: {\n  min: number;\n  max: number;\n  values: number[];\n  colors: string[];\n  direction?: Direction;\n  rtl?: boolean;\n}) =\u003e string;\n```\n\n`min`, `max`, `values` and `direction` should be same as for the `\u003cRange /\u003e` component. `colors` is a list of colors. This needs to be true:\n\n```js\nvalues.length + 1 === colors.length;\n```\n\nThat's because **one thumb** (one value) splits the track into **two segments**, so you need **two colors**.\n\n## Motivation\n\nThere is a native [input](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/range) solution:\n\n```html\n\u003cinput type=\"range\" /\u003e\n```\n\nHowever, it has some serious shortcomings:\n\n- vertical-oriented slider is [not supported in all browsers](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/range#Browser_compatibility)\n- supports only a single direction\n- very limited styling options\n- no support for multiple thumbs\n\nThere are also many `React` based solutions but most of them are too bloated, don't support styling through CSS in JS or have lacking performance.\n\n`react-range` has two main goals:\n\n- **Small footprint** - less then 4kB gzipped, single component.\n- **Bring your own styles and HTML markup** - `react-range` is a more low-level approach than other libraries. It doesn't come with any styling (except some positioning) or markup. It's up to the user to specify both! Think about `react-range` as a foundation for other styled input ranges.\n\n## End to end testing\n\n**This library is tightly coupled to many DOM APIs**. It would be very hard to ensure 100% test coverage just with unit tests that would not involve a lot of mocking. Or we could re-architect the library to better abstract all DOM interfaces but that would mean more code and bigger footprint.\n\nInstead of that, `react-range` adds thorough end to end tests powered by [playwright](https://playwright.dev/).\n\nAll tests are automatically ran in Travis CI with headless chromium. This way, the public API is well tested, including pixel-perfect positioning. Also, the tests are pretty fast, reliable and very descriptive.\n\nDo you want to run them in the `dev` mode (slows down operations, opens the browser)?\n\n```bash\npnpm ladle serve #start the ladle server\npnpm test:e2e:dev #run the e2e tests\n```\n\n`CI` mode (ladle started on the background, quick, headless)\n\n```bash\npnpm test:e2e\n```\n\n## Browser support\n\n- **Chrome** (latest, mac, windows, iOS, Android)\n- **Firefox** (latest, mac, windows)\n- **Safari** (latest, mac, iOS)\n- **Edge** (latest, windows)\n\n## Contributing\n\nThis is how you can spin up the dev environment:\n\n```\ngit clone https://github.com/tajo/react-range\ncd react-range\npnpm install\npnpm ladle serve\n```\n\n## Shoutouts 🙏\n\nBig big shoutout to **[Tom MacWright](https://macwright.org/)** for donating the `react-range` npm handle! ❤️\n\n## Author\n\nVojtech Miksu 2024, [miksu.cz](https://miksu.cz), [@vmiksu](https://twitter.com/vmiksu)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftajo%2Freact-range","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftajo%2Freact-range","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftajo%2Freact-range/lists"}