Svelte Audio UI
DocsParticles
0
Overview
  • Introduction
  • Get Started
Components
  • Audio Player
  • Audio Provider
  • Audio Queue
  • Audio Track
  • Audio Playback Speed
UI
  • Fader
  • Knob
  • Slider
  • Sortable List
  • XY Pad
Libs
  • Audio Store
  • HTML Audio
Resources
  • llms.txt
  • llms-full.txt

On This Page

InstallationUsageSize VariantsAPI ReferenceKnobPropsBehaviorExamplesFilter ControlMultiple KnobsRelated

Knob

Previous Next

A circular rotary control for adjusting values. Perfect for audio parameters, filters, and effects — with arc indicator, pointer drag, and keyboard support.


A pure Svelte knob built from plain HTML and SVG — no external primitives. Drag up/down to adjust, use keyboard arrows for fine control, and see value progress through a 270° arc indicator. Four size variants keep it fitting everywhere from compact effect panels to large master controls.

Loading...

<script lang="ts">
  import { Knob } from "$lib/components/ui/audio/elements/knob/index.js";
 
  let value = $state(50);
</script>
 
<div class="flex flex-col items-center gap-4">
  <Knob {value} onValueChange={(v) => (value = v)} />
  <span class="text-muted-foreground text-xs tabular-nums">{value}</span>
</div>

Installation

pnpm dlx shadcn-svelte@latest add https://svelte-audio-ui.vercel.app/r/knob.json
npx shadcn-svelte@latest add https://svelte-audio-ui.vercel.app/r/knob.json
npx shadcn-svelte@latest add https://svelte-audio-ui.vercel.app/r/knob.json
bun x shadcn-svelte@latest add https://svelte-audio-ui.vercel.app/r/knob.json

Copy and paste the following code into your project.

import Root, { type Size } from "./knob.svelte";

export { Root, type Size as KnobSize, Root as Knob };

Usage

<script lang="ts">
  import { Knob } from "$lib/components/ui/audio/elements/knob/index.js";
</script>
<Knob value={50} />

Size Variants

Loading...

<script lang="ts">
  import {
    Knob,
    type KnobSize
  } from "$lib/components/ui/audio/elements/knob/index.js";
 
  let sizes: { size: KnobSize; value: number }[] = $state([
    { size: "sm", value: 80 },
    { size: "default", value: 50 },
    { size: "lg", value: 60 },
    { size: "xl", value: 40 }
  ]);
</script>
 
<div class="flex flex-wrap items-end justify-center gap-8">
  {#each sizes as item (item.size)}
    <div class="flex flex-col items-center gap-2">
      <Knob
        size={item.size}
        value={item.value}
        onValueChange={(v) => {
          item.value = v;
        }}
      />
      <span class="text-muted-foreground text-xs">{item.size}</span>
    </div>
  {/each}
</div>

API Reference

Knob

Props

Prop Type Default Description
value number 50 Current value (bindable).
min number 0 Minimum value.
max number 100 Maximum value.
step number 1 Step increment.
disabled boolean false Disables all interaction and adds reduced-opacity.
size "sm" | "default" | "lg" | "xl" "default" Controls the knob diameter.
label string - Optional text label rendered above the knob.
onValueChange (value: number) => void - Fires on every change while the user interacts.
class string - Additional CSS classes on the root wrapper.

Behavior

  • Drag: Click and drag vertically — drag up to increase, drag down to decrease. 200 px of travel covers the full value range.
  • Keyboard: ArrowUp / ArrowRight increases; ArrowDown / ArrowLeft decreases by one step. Home jumps to min, End to max.
  • Arc indicator: A 270° SVG arc shows the track (dimmed) and the active fill from min to the current value.
  • Pointer indicator: The inner disc rotates with the value, with a small dot marking the exact position.

Tip: Use bind:value for two-way binding in Svelte, or pass value + onValueChange for a controlled setup.

Examples

Filter Control

Loading...

<script lang="ts">
  import { Knob } from "$lib/components/ui/audio/elements/knob/index.js";
 
  let frequency = $state(2000);
  let resonance = $state(30);
  let mix = $state(50);
 
  function formatFreq(hz: number) {
    return hz >= 1000 ? `${(hz / 1000).toFixed(1)}k` : `${hz}`;
  }
</script>
 
<div class="flex flex-wrap items-center justify-center gap-8">
  <div class="flex flex-col items-center gap-2">
    <Knob
      label="Freq"
      value={((frequency - 20) / (20000 - 20)) * 100}
      onValueChange={(v) =>
        (frequency = Math.round(20 + (v / 100) * (20000 - 20)))}
      size="lg"
    />
    <span class="text-muted-foreground text-xs tabular-nums"
      >{formatFreq(frequency)} Hz</span
    >
  </div>
 
  <div class="flex flex-col items-center gap-2">
    <Knob
      label="Res"
      value={resonance}
      onValueChange={(v) => {
        resonance = v;
      }}
      size="lg"
    />
    <span class="text-muted-foreground text-xs tabular-nums">{resonance}%</span>
  </div>
 
  <div class="flex flex-col items-center gap-2">
    <Knob
      label="Mix"
      value={mix}
      onValueChange={(v) => {
        mix = v;
      }}
      size="lg"
    />
    <span class="text-muted-foreground text-xs tabular-nums">{mix}%</span>
  </div>
</div>

Multiple Knobs

Loading...

<script lang="ts">
  import { Knob } from "$lib/components/ui/audio/elements/knob/index.js";
 
  let channels = $state([
    { label: "Vol", value: 80 },
    { label: "Pan", value: 50 },
    { label: "EQ Lo", value: 60 },
    { label: "EQ Hi", value: 40 },
    { label: "Reverb", value: 25 },
    { label: "Delay", value: 35 }
  ]);
</script>
 
<div class="flex flex-wrap items-center justify-center gap-6">
  {#each channels as channel (channel.label)}
    <div class="flex flex-col items-center gap-1">
      <Knob
        label={channel.label}
        value={channel.value}
        onValueChange={(v) => (channel.value = v)}
      />
      <span class="text-muted-foreground text-xs tabular-nums"
        >{channel.value}</span
      >
    </div>
  {/each}
</div>

Related

  • Fader — linear slider-style control for mixing boards
  • Audio Player — player controls to pair with knobs
  • Audio Provider — audio context and state management
Fader Slider
Built by ddtamn. The source code is available on Github