# Slosh Gauge

> Tank gauge whose liquid chases the value, tilts as it moves and splashes when it fills.

A tank gauge filled with liquid that chases its value on a spring. The surface leans while it moves, overshoots, and splashes back off the top or bottom when it slams in. Make it `interactive` to press or drag the tank to set the level, or step it with the arrow keys.

<demo-slosh-gauge>



</demo-slosh-gauge>

## Installation

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

## Usage

```vue
<script setup lang="ts">
  import { ref } from 'vue';
  import SloshGauge from '~/components/ui/slosh-gauge/SloshGauge.vue';

  const level = ref(60);
</script>

<template>
  <SloshGauge
    v-model="level"
    interactive
    liquid-color="#f5f5f5"
    glass-color="#27272a"
    :viscosity="0.15"
    :tilt="0.45"
    :splash="0.42"
  />
</template>
```

Without `interactive`, the gauge is a read-only `meter` that animates whenever `model-value` changes. Without `v-model`, it starts at `default-value`.

## 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>
      <code>
        undefined
      </code>
    </td>
    
    <td>
      The level, 0 to 100 (use <code>
        v-model
      </code>
      
      ). Every change launches the liquid toward it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        default-value
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        60
      </code>
    </td>
    
    <td>
      The starting level when uncontrolled.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        interactive
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Press or drag the tank to set the level, arrows to step. A marker shows the level.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        show-value
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        true
      </code>
    </td>
    
    <td>
      A readout whose colour flips at the surface.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        disabled
      </code>
    </td>
    
    <td>
      <code>
        boolean
      </code>
    </td>
    
    <td>
      <code>
        false
      </code>
    </td>
    
    <td>
      Dimmed and inert. Value changes still animate.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        liquid-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#f5f5f5'
      </code>
    </td>
    
    <td>
      The liquid. The readout over it picks dark or light by itself.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        glass-color
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '#27272a'
      </code>
    </td>
    
    <td>
      The tank.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        width
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        88
      </code>
    </td>
    
    <td>
      Tank width in px. The readout scales with it.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        height
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        180
      </code>
    </td>
    
    <td>
      Tank height in px.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        radius
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        20
      </code>
    </td>
    
    <td>
      Corner radius in px, capped at half the smaller side.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        ticks
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        4
      </code>
    </td>
    
    <td>
      Lines etched on the right of the glass. <code>
        0
      </code>
      
       hides them.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        viscosity
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.15
      </code>
    </td>
    
    <td>
      <code>
        0
      </code>
      
       is a rigid gauge. Higher is slower to answer, longer to settle, and overshoots more.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        tilt
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.45
      </code>
    </td>
    
    <td>
      How far the surface leans per unit of speed. <code>
        0
      </code>
      
       keeps it flat.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        splash
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      <code>
        0.42
      </code>
    </td>
    
    <td>
      How much of a slam the top and bottom give back. <code>
        0
      </code>
      
       swallows it, <code>
        0.8
      </code>
      
       nearly bounces.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        unit
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        '%'
      </code>
    </td>
    
    <td>
      Readout suffix.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        aria-label
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        'Level'
      </code>
    </td>
    
    <td>
      Accessible name of the meter or slider.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        class
      </code>
    </td>
    
    <td>
      <code>
        string
      </code>
    </td>
    
    <td>
      <code>
        ''
      </code>
    </td>
    
    <td>
      Extra classes for the tank.
    </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>
        number
      </code>
    </td>
    
    <td>
      The integer level on press, on each change while dragging, and on keys.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        change
      </code>
    </td>
    
    <td>
      <code>
        number
      </code>
    </td>
    
    <td>
      Same as above, for listeners that do not use <code>
        v-model
      </code>
      
      .
    </td>
  </tr>
</tbody>
</table>

## Accessibility

- Read-only gauges are a `meter`; interactive ones are a vertical `slider` with `aria-valuenow` kept in sync with the level.
- Arrow keys step by 2 (10 with Shift), Page Up and Page Down step by 10, Home and End jump to 0 and 100.
- Escape during a drag puts the level back where the drag started.
- Grabbing near the current level drags it relatively; pressing elsewhere jumps to that point.
- With `prefers-reduced-motion`, the surface stays flat, the spring is critically damped and nothing splashes.
- Ported from [React Bits](https://reactbits.dev/micro/slosh-gauge) by David Haz.
