Lab

Knob

The <audio-ui-knob> custom element of @audio-ui/elements: its attributes, its parts and a live preview.

<audio-ui-knob> is the root of a rotary control. It owns the value and renders its parts from it.

Usage

The styles read the theme's CSS variables, which Styling sets.

<style>
  audio-ui-knob {
    position: relative;
    display: inline-flex;
    width: calc(var(--spacing, 0.25rem) * 12);
    height: calc(var(--spacing, 0.25rem) * 12);
    margin-bottom: calc(var(--spacing, 0.25rem) * 8);
    outline: none;
  }

  audio-ui-knob-control {
    position: relative;
    isolation: isolate;
    display: flex;
    width: 100%;
    height: 100%;
    clip-path: circle(50% at 50% 50%);
    cursor: grab;
    outline: none;
    touch-action: none;
    user-select: none;
  }

  audio-ui-knob-control:active {
    cursor: grabbing;
  }

  /* The knob's face. */
  audio-ui-knob-control::before {
    content: "";
    position: absolute;
    inset: calc(var(--spacing, 0.25rem) * 1.5);
    border-radius: 9999px;
    background: var(--card, oklch(1 0 0));
    box-shadow: 0 0 0 1px color-mix(in oklab, var(--foreground, oklch(0.145 0 0)) 10%, transparent);
  }

  audio-ui-knob-track,
  audio-ui-knob-indicator {
    position: absolute;
    inset: 0;
    z-index: 1;
    display: block;
    width: 100%;
    height: 100%;
    color: var(--primary, oklch(0.205 0 0));
    pointer-events: none;
  }

  audio-ui-knob-track {
    opacity: 0.22;
  }

  audio-ui-knob-track path,
  audio-ui-knob-indicator path {
    stroke: currentColor;
  }

  audio-ui-knob-thumb {
    position: absolute;
    inset: 0;
    z-index: 2;
    color: var(--primary, oklch(0.205 0 0));
    pointer-events: none;
  }

  /* The mark on the face: the thumb turns with the value. */
  audio-ui-knob-thumb::after {
    content: "";
    position: absolute;
    top: 24%;
    left: 50%;
    width: 6%;
    height: 15%;
    translate: -50% 0;
    border-radius: 9999px;
    background: currentColor;
  }

  audio-ui-knob-value {
    position: absolute;
    top: 100%;
    left: 50%;
    z-index: 10;
    margin-top: calc(var(--spacing, 0.25rem) * 1);
    padding: calc(var(--spacing, 0.25rem) * 0.5) calc(var(--spacing, 0.25rem) * 1.5);
    translate: -50% 0;
    border-radius: calc(var(--radius, 0.625rem) - 4px);
    background: var(--foreground, oklch(0.145 0 0));
    color: var(--background, oklch(1 0 0));
    font-size: 10px;
    font-weight: 500;
    line-height: 1;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    pointer-events: none;
  }

  audio-ui-knob-label {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border-width: 0;
  }
</style>

<audio-ui-knob min="0" max="100" value="40">
  <audio-ui-knob-label>Volume</audio-ui-knob-label>
  <audio-ui-knob-control>
    <audio-ui-knob-track></audio-ui-knob-track>
    <audio-ui-knob-indicator></audio-ui-knob-indicator>
    <audio-ui-knob-thumb></audio-ui-knob-thumb>
  </audio-ui-knob-control>
  <audio-ui-knob-value></audio-ui-knob-value>
</audio-ui-knob>

<script type="module">
  import "@audio-ui/elements/knob";

  const knob = document.querySelector("audio-ui-knob");
  knob.addEventListener("input", (event) =>
    console.log(event.detail.value)
  );
</script>

API reference

pnpm add @audio-ui/elements
import "@audio-ui/elements/knob";
ExportKindWhat it is
KNOB_TAGSconstThe names the knob's elements are registered under, frozen: a page cannot rename them by accident.
KnobChangeEventtypeFired once a gesture ends with a new value.
KnobControlElementclassThe interactive surface.
KnobElementclassThe root of a rotary control.
KnobElementEventMapinterfaceThe events a knob fires, as addEventListener types them.
KnobEventDetailinterfaceWhat a knob's input and change events carry, besides the knob itself as their target.
KnobIndicatorElementclassThe arc from anchor to the value, rendered over the track.
KnobInputEventtypeFired on every change.
KnobLabelElementclassThe accessible label.
KnobThumbElementclassRotates with the value, clockwise from 12 o'clock, through rotate.
KnobTrackElementclassThe full sweep of the dial, rendered as an SVG arc in currentColor.
KnobValueElementclassRenders the value, formatted with the knob's format and locale.

Props · 13

PartDescription
<audio-ui-knob-control>The interactive surface: pointer drag, wheel, double tap or Alt + click to reset
<audio-ui-knob-track>The full sweep, drawn as an SVG arc. stroke-width sets its width in the 48×48 viewBox (3 by default)
<audio-ui-knob-indicator>The arc from anchor to the value
<audio-ui-knob-thumb>Rotates with the value and contains the native range input, to which its aria-label, aria-labelledby and aria-describedby are moved
<audio-ui-knob-value>The formatted value
<audio-ui-knob-label>Labels the input when the thumb has no accessible name

The same control in React, and its parts' props: Knob.

Built by Ouest Labs, the source code is available on GitHub.
RSS