Slider

Slider

The Slider component is a range control with mouse, touch, and keyboard support. It renders with an <input type="hidden">, in case it needs to be embedded in a vanilla form.

Keys that interact with the slider when focused:

, , , , page up, page down, home, and end

Focus behavior

The slider is focused when interacting with it (by clicking, touching, or tabbing to it), and will fire the onFocus & onBlur events as expected. Visually, it does not appear focused when clicking or touching (since it’s obvious to the user they are interacting with it & the style is distracting).

Props

name type default description
className string Class names for the root element (which has the .Slider class)
disabled boolean false When true, the slider appears disabled and is not interactive
max number 100 The highest possible number that value can be
min number 0 The lowest possible number that value can be
name string Added to the the hidden <input>
onChange callback Called when the value changes (the value does change continuously while the slider is dragged)
onDragEnd callback Called once when the slider stops dragging
onDragStart callback Called once when the slider starts dragging
required boolean Added to the hidden <input>
step number 1 value is restricted to increments of this number
tabIndex number 0 Applied to the root element so the slider can be focused using the keyboard. Change to -1 to disable that
value number Current value (you need to pass this back down when onChange is called, so the slider can appear to move)
...other All other props (such as onFocus) are applied to the root element

Modifiers

class notes
Slider--is-disabled Automatically applied by the react component
Slider--is-focused Automatically applied by the react component
<div>
    <div class="mb7">
        <div role="slider" aria-valuemax="100" aria-valuemin="0" aria-valuenow="50" class="Slider" tabindex="0">
            <div class="Slider__track-line"></div>
            <div class="Slider__track">
                <div class="Slider__fill" style="right:50%;">
                    <div class="Slider__handle"></div>
                </div>
            </div>
            <input type="hidden" step="1" min="0" max="100" value="50" />
        </div>
        <div class="mt1 text-color-secondary text-2"><code>{&quot;value&quot;:50,&quot;min&quot;:0,&quot;max&quot;:100,&quot;step&quot;:1}</code>
        </div>
    </div>
    <div class="mb7">
        <div role="slider" aria-valuemax="2" aria-valuemin="1" aria-valuenow="1.75" class="Slider" tabindex="0">
            <div class="Slider__track-line"></div>
            <div class="Slider__track">
                <div class="Slider__fill" style="right:25%;">
                    <div class="Slider__handle"></div>
                </div>
            </div>
            <input type="hidden" step="0.01" min="1" max="2" value="1.75" />
        </div>
        <div class="mt1 text-color-secondary text-2"><code>{&quot;value&quot;:1.75,&quot;min&quot;:1,&quot;max&quot;:2,&quot;step&quot;:0.01}</code>
        </div>
    </div>
    <div class="mb7">
        <div role="slider" aria-valuemax="100" aria-valuemin="0" aria-valuenow="25" class="Slider Slider--is-disabled" tabindex="-1">
            <div class="Slider__track-line"></div>
            <div class="Slider__track">
                <div class="Slider__fill" style="right:75%;">
                    <div class="Slider__handle"></div>
                </div>
            </div>
            <input type="hidden" step="1" min="0" max="100" value="25" />
        </div>
        <div class="mt1 text-color-secondary text-2"><code>{&quot;value&quot;:25,&quot;min&quot;:0,&quot;max&quot;:100,&quot;step&quot;:1,&quot;disabled&quot;:true}</code>
        </div>
    </div>
</div>
import * as React from 'react';
import Slider from './slider.jsx';

export default function demos() {
  return (
    <div>
      <SliderDemo value={50} min={0} max={100} step={1} />
      <SliderDemo value={1.75} min={1} max={2} step={0.01} />
      <SliderDemo value={25} min={0} max={100} step={1} disabled />
    </div>
  );
}

class SliderDemo extends React.Component {
  constructor(props, context) {
    super(props, context);
    this.state = { value: props.value };
  }

  render() {
    const props = { ...this.props, value: this.state.value };

    return (
      <div className="mb7">
        <Slider
          {...props}
          onChange={newValue => {
            this.setState({ value: newValue });
          }}
        />
        <div className="mt1 text-color-secondary text-2">
          <code>{JSON.stringify(props)}</code>
        </div>
      </div>
    );
  }
}
/* No context defined for this component. */
  • Content:
    $slider-handle-size: modular-scale-px(3);
    $slider-track-height: 3px;
    $slider-track-offset: floor(($slider-handle-size / 2) - ($slider-track-height / 2));
    $slider-track-border-radius: $slider-track-height / 2;
    $slider-focus-margin: modular-scale-px(-6);
    $slider-focus-size: $slider-handle-size - ($slider-focus-margin * 2);
    $slider-focus-color: $blue-100;
    
    .Slider {
      cursor: pointer;
      height: $slider-handle-size;
      position: relative;
    
      &:focus {
        outline: none;
      }
    }
    
    .Slider__track-line {
      border-radius: $slider-track-border-radius;
      height: $slider-track-height;
      left: 0;
      position: absolute;
      right: 0;
      top: $slider-track-offset;
    }
    
    .Slider__track {
      bottom: 0;
      left: $slider-handle-size / 2;
      position: absolute;
      right: $slider-handle-size / 2;
      top: 0;
    }
    
    .Slider__fill {
      border-radius: $slider-track-border-radius 0 0 $slider-track-border-radius;
      height: $slider-track-height;
      left: -1 * $slider-handle-size / 2;
      position: absolute;
      top: $slider-track-offset;
    }
    
    .Slider__handle {
      @include depth(7);
      border-radius: 50%;
      height: $slider-handle-size;
      position: absolute;
      right: -1 * $slider-handle-size / 2;
      top: -1 * $slider-track-offset;
      width: $slider-handle-size;
    
      &::after {
        background-color: $slider-focus-color;
        border-radius: 50%;
        bottom: $slider-focus-margin;
        box-shadow: 0 0 ($slider-focus-size / 2) 0 rgba($slider-focus-color, $alpha-700);
        content: '';
        left: $slider-focus-margin;
        opacity: 0;
        position: absolute;
        right: $slider-focus-margin;
        top: $slider-focus-margin;
        transition: opacity .15s linear;
      }
    }
    
    .Slider--is-disabled {
      cursor: not-allowed;
      opacity: $alpha-500;
    }
    
    .Slider--is-focused {
      .Slider__handle::after {
        opacity: 1;
      }
    }
    
    @mixin slider-color($fill-color, $track-color: rgba($black, $alpha-300), $handle-color: $white) {
      .Slider__track-line {
        background-color: $track-color;
      }
    
      .Slider__fill {
        background-color: $fill-color;
      }
    
      .Slider__handle {
        background-color: $handle-color;
      }
    }
    
    @mixin slider-green {
      @include slider-color($green-200);
    }
    
    @include slider-green;
    
  • URL: /components/raw/slider/_slider.scss
  • Filesystem Path: library/components/slider/_slider.scss
  • Size: 2.1 KB