https://github.com/Stanko/dual-range-input
Native dual range input in 80 lines of TypeScript.
https://github.com/Stanko/dual-range-input
Last synced: 4 months ago
JSON representation
Native dual range input in 80 lines of TypeScript.
- Host: GitHub
- URL: https://github.com/Stanko/dual-range-input
- Owner: Stanko
- License: mit
- Created: 2024-11-15T22:26:56.000Z (5 months ago)
- Default Branch: dev
- Last Pushed: 2024-12-13T16:20:09.000Z (4 months ago)
- Last Synced: 2024-12-13T17:37:28.547Z (4 months ago)
- Language: TypeScript
- Homepage: http://muffinman.io/dual-range-input/
- Size: 83 KB
- Stars: 124
- Watchers: 1
- Forks: 2
- Open Issues: 2
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.md
Awesome Lists containing this project
- my-awesome-list - dual-range-input
README
# Native Dual-range Input
The native part is somewhat open for discussion - the library uses two native range inputs
and about [sixty lines of JavaScript](https://cdn.jsdelivr.net/npm/@stanko/dual-range-input/dist/index.js) to make them work together.
In my book, it is _native enough_.If you are interested in how it works, please check the [blog post](https://muffinman.io/blog/native-dual-range-input).
## Usage
Install it:
```bash
npm install @stanko/dual-range-input
```Add the required markup:
```html
```Import the CSS file located at:
```
./node_modules/@stanko/dual-range-input/dist/index.css
```Instantiate the library:
```js
import DualRangeInput from '@stanko/dual-range-input';const $min = document.querySelector('#min');
const $max = document.querySelector('#max');new DualRangeInput($min, $max);
// Add native event handlers
$min.addEventListener('input', () => {
// ...
});
```### Parameters
- **$min** `HTMLInputElement` - The range input element for the minimum value
- **$max** `HTMLInputElement` - The range input element for the maximum value
- **precision** `number`, optional, defaults to 3 - The number of decimal places to round the mid value to## Styling
Styles are controlled using CSS variables.
Here are all of the variables and their default values:
```css
/* Height of the input */
--dri-height: 1.5rem;/* Thumb size */
--dri-thumb-width: 1.25rem;
--dri-thumb-height: 1.25rem;/* Thumb background color */
--dri-thumb-color: #ddd;
--dri-thumb-hover-color: #a8d5ff;
--dri-thumb-active-color: #4eaaff;/* Thumb border */
--dri-thumb-border-color: rgba(0, 0, 0, 0.1);
--dri-thumb-border-hover-color: var(--dri-thumb-border-color);
--dri-thumb-border-active-color: var(--dri-thumb-border-color);
--dri-thumb-border-radius: 1rem;
--dri-thumb-border-width: 1px;/* Track size */
--dri-track-height: 0.25rem;
--dri-track-border-radius: 1rem;/* Track color */
--dri-track-color: #ccc;
--dri-track-filled-color: #0084ff;
```Please note that `--dri-thumb-width` is used by the library through the CSS `calc()` methods.
### Custom theme
To create your own theme, just change the variables. For example here is code for the purple example from the demo page:
```scss
.dual-range-input--purple {
--dri-thumb-width: 2rem;
--dri-thumb-height: 2rem;--dri-thumb-color: #ddd;
--dri-thumb-active-color: #682af8;
--dri-thumb-hover-color: #b697ff;--dri-track-filled-color: #682af8;
--dri-height: 2rem;
}
```This gives you:

You can find more examples in the [demo SCSS file](./demo/index.scss).
### :focus-visible styles
These are the default focus styles, feel free to override them.
```scss
.dual-range-input:has(input:focus-visible) {
outline: 2px solid var(--dri-thumb-active-color);
outline-offset: 4px;
border-radius: 4px;
}
```## API
- `update(method: 'floor' | 'ceil' = 'ceil')`
The main method that updates the mid-point and the gradient fill. You should call it only when you make direct changes to one of the input's value.
`method` is the rounding method used for the mid-point. It is used only when the midpoint falls between two tickmarks. In the case of direct value changes, this doesn't matter much. However, the library uses `ceil` when the minimum input is updated and `floor` when the maximum input is updated.
```js
const priceInput = new DualRangeInput($min, $max);$min.value = 20;
priceInput.update('ceil');$max.value = 37;
priceInput.update('floor');
```- `destroy()`
Removes event listeners set by the library.
```js
const priceInput = new DualRangeInput($min, $max);priceInput.destroy();
```## WebComponent
For now, for those who prefer WebComponents, here is a simple example:
```js
import DualRangeInput from '@stanko/dual-range-input';class DualRangeInputWebComponent extends HTMLElement {
constructor() {
super();const $min = this.querySelector('input[type=range]:first-child');
const $max = this.querySelector('input[type=range]:nth-child(2)');new DualRangeInput($min, $max);
}
}customElements.define('dual-range-input', DualRangeInputWebComponent);
```## TODO
- [x] Remove highlight on tap, on mobile
- [x] Update readme
- [x] Publish the package
- [x] RTL
- [x] Write a blog post
- [ ] Add (p)react version
- [ ] Explore web component approach## Other
- Library is only available as ESM module.
- Library doesn't include border around the track, it just feels too hacky. But here is the code if you want to use it:```scss
.dual-range-input {
--dri-track-border-color: #ccc;
position: relative;&::before {
content: '';
display: block;
position: absolute;
background-color: var(--dri-track-border-color);
border-radius: var(--dri-track-border-radius);
// Make it stick 1px on each side
height: calc(var(--dri-track-height) + 2px);
left: -1px;
right: -1px;
// Center it vertically
top: 50%;
transform: translateY(-50%);
}input {
// Put the inputs above it
position: relative;
z-index: 1;
}
}
```