# Slider (w-slider)

## Description

Parent component for sliders (both single and range sliders). Used in combination with a `<w-slider-thumb>`.

[Warp component reference](https://warp-ds.github.io/docs/components/slider/frameworks/elements)

## Usage

A slider consists of two custom elements that work together:

- `<w-slider>` - A container that creates a `<fieldset>` and coordinates shared state and attributes.
- `<w-slider-thumb>` - The `<input type="range">`, tooltip and text field for each slider in the range (from and to values).

Sliders come in two main variants:

- Single slider with one thumb and one input field.
- Range slider with two thumbs and input fields.

## Accessibility

## Examples

### Single slider

<elements-example>

```html
<form id="audio">
  <w-slider label="Volume" min="0" max="100">
    <w-slider-thumb name="volume"></w-slider-thumb>
  </w-slider>
</form>
```

</elements-example>

### Range slider

<elements-example>

```html
<w-slider label="Range" min="0" max="100">
  <w-slider-thumb
    slot="from"
    aria-label="From value"
    name="from"
  ></w-slider-thumb>
  <w-slider-thumb slot="to" aria-label="To value" name="to"></w-slider-thumb>
</w-slider>
```

</elements-example>

### Open ended range slider

An open ended range slider covers a case where you want to offer a selection in a common range of values, but allow values outside of that range.

In the example below the case is production year. The edges of the open ended range slider are taken to mean "anything before 1950" and "anything after 2025". This is indicated by an empty string value (`""`).

Users can also choose to enter values into the input field that are outside the range of the slider, for example `1932` or `2027`.

<elements-example>
  
```html
<form id="openended">
  <w-slider label="Production year" min="1950" max="2025" open-ended data-testid="open-ended">
    <w-slider-thumb slot="from" name="from-year"></w-slider-thumb>
    <w-slider-thumb slot="to" name="to-year"></w-slider-thumb>
  </w-slider>
</form>
<script>
  const openEndedSlider = document.querySelector('w-slider[data-testid="open-ended"]');
  openEndedSlider.labelFormatter = function (slot) {
    if (slot === "from") {
      return "Before 1950";
    }
    return "2025+";
  };
  
  openEndedSlider.valueFormatter = function (value, slot) {
    if (slot === "from" && value === "") {
      return "Min";
    }
    if (slot === "to" && value === "") {
      return "Max";
    }
    return value;
  };
</script>

```

</elements-example>

### Suffix in the input field

You can set a `suffix` on `<w-slider>` and have it apply to any input field in the component.

<elements-example>

```html
<w-slider
  label="Apartment size"
  min="0"
  max="250"
  suffix="sqm"
>
  <w-slider-thumb
    slot="from"
    aria-label="From size"
    name="from"
  ></w-slider-thumb>
  <w-slider-thumb
    slot="to"
    aria-label="To size"
    name="to"
  ></w-slider-thumb>
</w-slider>
```

</elements-example>

### Number formatter

If you need to format numbers, use the [`valueFormatter`](#valueformatter) and [`labelFormatter`](#labelFormatter) properties.

<elements-example >

```html
<w-slider label="Price" min="0" max="250000" suffix="kr" data-testid="currency">
  <w-slider-thumb
    slot="from"
    aria-label="From price"
    name="from"
  ></w-slider-thumb>
  <w-slider-thumb slot="to" aria-label="To price" name="to"></w-slider-thumb>
</w-slider>
<script>
  const numberFormatter = new Intl.NumberFormat("en", {
    maximumFractionDigits: 0,
  }).format;
  const currencySlider = document.querySelector('w-slider[data-testid="currency"]');
  currencySlider.valueFormatter = numberFormatter;
  currencySlider.labelFormatter = (slot) => {
    if (slot === "from") return "0";
    return numberFormatter("250000");
  };
</script>
```

</elements-example>

### Steps

Sets the [`step` HTML attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/step) on the inputs.

<elements-example>

```html
<w-slider label="Single" step="5" min="0" max="100">
  <w-slider-thumb name="value"></w-slider-thumb>
</w-slider>
```

</elements-example>

### Marks

Show tick markers along the slider. Only works with a single slider.

<elements-example>

```html
<w-slider label="Single" min="0" max="100" step="5" markers="5">
  <w-slider-thumb name="value"></w-slider-thumb>
</w-slider>
```

</elements-example>

### With help text

<elements-example>

```html
<w-slider
  label="Model year"
  min="1950"
  max="2025"
  help-text="Model year of the car"
>
  <w-slider-thumb slot="from" name="from"></w-slider-thumb>
  <w-slider-thumb slot="to" name="to"></w-slider-thumb>
</w-slider>
```

</elements-example>

### With validation error

<elements-example>

```html
<w-slider
  label="Model year"
  min="1950"
  max="2025"
  error="Something is wrong and this should help you solve the problem"
  invalid
>
  <w-slider-thumb slot="from" name="from"></w-slider-thumb>
  <w-slider-thumb slot="to" name="to"></w-slider-thumb>
</w-slider>
```

</elements-example>

### Visually hidden labels

<elements-example>

```html
<w-slider min="1950" max="2025" help-text="Model year of the car">
  <legend class="sr-only" slot="label">Model year</legend>
  <w-slider-thumb slot="from" name="from"></w-slider-thumb>
  <w-slider-thumb slot="to" name="to"></w-slider-thumb>
</w-slider>
```

</elements-example>

### Hidden min and max value labels

Give the component a label formatter and always return the empty string.

<elements-example>

```html
<w-slider min="1950" max="2025" help-text="Model year of the car" data-testid="hidden-minmax-label">
  <legend class="sr-only" slot="label">Model year</legend>
  <w-slider-thumb slot="from" name="from"></w-slider-thumb>
  <w-slider-thumb slot="to" name="to"></w-slider-thumb>
</w-slider>
<script>
  const hiddenMinMaxSlider = document.querySelector('w-slider[data-testid="hidden-minmax-label"]');
  hiddenMinMaxSlider.labelFormatter = () => "";
</script>
```

</elements-example>

### Visually hiden text field

The text field doubles as a visualization of the exact value, which is difficult to see on a slider. If you visually hide the text field with the `hidden-textfield` attribute always make sure to show the value some place, unless the exact value is irrellevant.

<elements-example>

```html
<output class="text-xs">
  <span class="font-bold">Distance:</span>
  <span data-testid="distance-value"></span>
</output>
<form name="map">
  <w-slider min="0" max="20" hidden-textfield data-testid="map-radius">
    <legend class="sr-only" slot="label">Location filter radius</legend>
    <w-slider-thumb name="distance"></w-slider-thumb>
  </w-slider>
</form>
<script>
  const mapRadiusSlider = document.querySelector('w-slider[data-testid="map-radius"]');

  const radiusSteps = [
    200, 300, 400, 500, 700, 1000, 1500, 2000, 3000, 5000, 7000, 10000, 20000,
    30000, 50000, 75000, 100000, 200000, 300000, 400000, 500000,
  ];
  const formatter = new Intl.NumberFormat("en", { maximumFractionDigits: 0 });
  
  const formatDistance = (value) => {
    const index = Number.parseInt(value);
    const numValue = radiusSteps[index];

    let formattedValue = "";

    if (numValue < 1000) {
      formattedValue = formatter.format(numValue) + " m";
    } else {
      formattedValue = formatter.format(numValue / 1000) + " km";
    }
    return formattedValue;
  };
  
  mapRadiusSlider.labelFormatter = (slot) => {
    if (slot === "from") {
      return formatDistance("0");
    }
    return formatDistance(String(radiusSteps.length - 1));
  };
  
  mapRadiusSlider.valueFormatter = (value) => {
    const formattedValue = formatDistance(value);
    document.querySelector('[data-testid="distance-value"]').innerText = formattedValue;
    return formattedValue;
  };
</script>
```

</elements-example>

## Styling API

## `<w-slider>` API

Unless otherwise noted all properties are HTML attributes (as opposed to JavaScript object properties).

### Properties

| Name | Type | Default | Summary |
|-|-|-|-|
| _label (JS only) | `unknown` | `-` | - |
| disabled | `boolean` | `false` | - |
| error | `string \| undefined` | `-` | Validation error text, if any |
| help-text | `string \| undefined` | `-` | Additional description to show below the fieldset |
| hidden-textfield | `boolean` | `false` | Should only be used in special cases |
| invalid | `boolean` | `false` | Sets the form fields and fieldset in an invalid state |
| label | `string \| undefined` | `-` | The slider fieldset label. Required for proper accessibility. |
| labelFormatter (JS only) | `((slot: SliderSlot) => string) \| undefined` | `-` | Formatter for the min and max labels below the range. |
| markers | `number \| undefined` | `-` | Pass a value similar to step to create visual markers at that interval |
| max | `string \| undefined` | `100` | The maximum allowed value in the range inputs |
| min | `string \| undefined` | `0` | The minimum allowed value in the range inputs |
| open-ended | `boolean` | `false` | Whether or not to allow values outside the range such as "Before 1950" and "2025+". |
| optional | `boolean` | `false` | Whether to show the optional indicator after the label. |
| required | `boolean` | `false` | Ensures a child slider thumb has a value before allowing the containing form to submit |
| step | `number \| undefined` | `-` | ets step on the range input to jump between values when dragging |
| suffix | `string \| undefined` | `-` | Suffix used in text input fields and for the min and max values of the slider |
| tooltipFormatter (JS only) | `((value: string, slot: SliderSlot) => string) \| undefined` | `-` | Overrides valueFormatter for the tooltip. |
| valueFormatter (JS only) | `((value: string, slot: SliderSlot) => string) \| undefined` | `-` | Formatter for the tooltip and input mask values |

### Property Details

#### _label (JS only)



- Type: `unknown`
- Default: `-`

#### disabled



- Type: `boolean`
- Default: `false`

#### error

Validation error text, if any

- Type: `string | undefined`
- Default: `-`

#### help-text

Additional description to show below the fieldset

- Type: `string | undefined`
- Default: `-`

#### hidden-textfield

Should only be used in special cases

- Type: `boolean`
- Default: `false`

#### invalid

Sets the form fields and fieldset in an invalid state

- Type: `boolean`
- Default: `false`

#### label

The slider fieldset label. Required for proper accessibility.

If you need to display HTML, use the `label` slot instead (f. ex. `<legend class="sr-only" slot="label">Production year</legend>`)

- Type: `string | undefined`
- Default: `-`

#### labelFormatter (JS only)

Formatter for the min and max labels below the range.

- Type: `((slot: SliderSlot) => string) | undefined`
- Default: `-`

#### markers

Pass a value similar to step to create visual markers at that interval

- Type: `number | undefined`
- Default: `-`

#### max

The maximum allowed value in the range inputs

- Type: `string | undefined`
- Default: `100`

#### min

The minimum allowed value in the range inputs

- Type: `string | undefined`
- Default: `0`

#### open-ended

Whether or not to allow values outside the range such as "Before 1950" and "2025+".

- Type: `boolean`
- Default: `false`

#### optional

Whether to show the optional indicator after the label.

- Type: `boolean`
- Default: `false`

#### required

Ensures a child slider thumb has a value before allowing the containing form to submit

- Type: `boolean`
- Default: `false`

#### step

ets step on the range input to jump between values when dragging

- Type: `number | undefined`
- Default: `-`

#### suffix

Suffix used in text input fields and for the min and max values of the slider

- Type: `string | undefined`
- Default: `-`

#### tooltipFormatter (JS only)

Overrides valueFormatter for the tooltip.

Use in open-ended sliders to show for example "300+ hk" instead of "Max" in the tooltip.

- Type: `((value: string, slot: SliderSlot) => string) | undefined`
- Default: `-`

#### valueFormatter (JS only)

Formatter for the tooltip and input mask values

- Type: `((value: string, slot: SliderSlot) => string) | undefined`
- Default: `-`

