# Wake Slider

> Thumbless range slider of thin bars where drag speed raises a wake behind the handle.

A range slider drawn as a row of thin bars, with no thumb. Bars up to the value are lit. Drag fast and the bars around the handle rise into a wake that trails behind it; drag slowly and the row stays flat. Arrow keys, Page Up/Down, Home and End move it in steps.

<demo-wake-slider>



</demo-wake-slider>

## Installation

```bash
npx shadcn-vue@latest add "https://nxui.geoql.in/r/wake-slider.json"
```

## Usage

```vue
<script setup lang="ts">
  import { ref } from 'vue';
  import WakeSlider from '~/components/ui/wake-slider/WakeSlider.vue';

  const volume = ref(50);

  function percent(value: number) {
    return `${value}%`;
  }
</script>

<template>
  <WakeSlider
    v-model="volume"
    :bars="32"
    :reach="6"
    :skew="0.6"
    crest-color="#a855f7"
    show-value
    :format-value="percent"
    aria-label="Volume"
  />
</template>
```

The handle position follows the value through a critically damped spring (`glide` seconds to settle). Its velocity, smoothed by a second spring (`smoothing` ms), sets the wake height. Each bar near the handle lifts by a cosine-squared profile that reaches further behind the motion than ahead of it (`skew`).

## Props

<table>
<thead>
  <tr>
    <th>
      Prop
    </th>
    
    <th>
      Type
    </th>
    
    <th>
      Default
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        model-value
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      Controlled value (<code>
        v-model
      </code>
      
      ).
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        default-value
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        50
      </code>
    </td>
    
    <td>
      Initial value when uncontrolled.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        min
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
    </td>
    
    <td>
      Lowest value.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        max
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        100
      </code>
    </td>
    
    <td>
      Highest value.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        step
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      Snapping grid. Large steps move the handle in notches; the wake pulses per notch.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        bars
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        32
      </code>
    </td>
    
    <td>
      How many bars draw the track.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        height
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        56
      </code>
    </td>
    
    <td>
      Full bar height in pixels, the ceiling of the wake.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        rest-height
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        12
      </code>
    </td>
    
    <td>
      Bar height at rest in pixels.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        gap
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        4
      </code>
    </td>
    
    <td>
      Space between bars in pixels.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        fill-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'var(--foreground)'
      </code>
    </td>
    
    <td>
      Lit bars, up to the value.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        track-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'var(--muted)'
      </code>
    </td>
    
    <td>
      Unlit bars.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        crest-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      Optional tint the raised bars take on by their lift. Empty renders no tint layer.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        sensitivity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        1
      </code>
    </td>
    
    <td>
      How easily speed raises the wake. Low needs a flick; high lifts on a stroll.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        reach
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        6
      </code>
    </td>
    
    <td>
      Half-width of the wake at full speed, in bars.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        skew
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.6
      </code>
    </td>
    
    <td>
      How much wider the wake is behind the handle than ahead. 0 is symmetric.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        glide
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.3
      </code>
    </td>
    
    <td>
      Seconds the handle takes to settle. Short hugs the finger; long floats.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        smoothing
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        100
      </code>
    </td>
    
    <td>
      Milliseconds of velocity lag. Low twitches; high lingers.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        show-value
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Shows the value beside the track.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        format-value
      </code>
    </td>
    
    <td>
      <code>
        (value: number) => string
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      Formats the readout and the announced value.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        disabled
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Fades the slider and ignores input.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        aria-label
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'Value'
      </code>
    </td>
    
    <td>
      Accessible name of the slider.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        class
      </code>
    </td>
    
    <td>
      <code>
        HTMLAttributes['class']
      </code>
    </td>
    
    <td>
      —
    </td>
    
    <td>
      Extra classes for the root.
    </td>
  </tr>
</tbody>
</table>

## Events

<table>
<thead>
  <tr>
    <th>
      Event
    </th>
    
    <th>
      Payload
    </th>
    
    <th>
      Description
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        update:modelValue
      </code>
    </td>
    
    <td>
      <code>
        (value: number)
      </code>
    </td>
    
    <td>
      Every committed change, from the pointer or the keyboard.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        change
      </code>
    </td>
    
    <td>
      <code>
        (value: number)
      </code>
    </td>
    
    <td>
      Same as above, for uncontrolled use.
    </td>
  </tr>
</tbody>
</table>

## Accessibility

- The track holds a full-size `role="slider"` button with `aria-valuemin`, `aria-valuemax`, `aria-valuenow` and `aria-valuetext` (from `format-value`).
- Arrow keys move one step, Page Up/Down ten steps, Home/End jump to the ends. Keyboard moves skip the wake and jump straight to the value.
- Keyboard focus shows a ring around the track.
- With `prefers-reduced-motion: reduce` the bars never rise; only the lit range changes.
- Ported from [React Bits](https://reactbits.dev/micro/wake-slider) by David Haz.
