SvRepeatButton

A button that keeps firing while you hold it down - after an initial delay, then at a steady interval.

SvRepeatButton is the press-and-hold primitive behind steppers, spinners, and volume or seek controls. A single click fires onclick once; holding it fires once immediately, waits delay ms, then repeats every interval ms until you release, leave the button, or lift the pointer anywhere on the page. It shares SvButton's visual language (variants and sizes) so it drops into a toolbar unchanged.

Basic usage

<script lang="ts">
  import { SvRepeatButton } from '@svgrid/grid'
  let qty = $state(1)
</script>

<SvRepeatButton ariaLabel="Decrease" onclick={() => (qty = Math.max(0, qty - 1))}>-</SvRepeatButton>
<span>{qty}</span>
<SvRepeatButton ariaLabel="Increase" onclick={() => (qty += 1)}>+</SvRepeatButton>

Props

Prop Type Default Description
onclick () => void - Fires once per click, then repeatedly while held.
delay number 300 Milliseconds to wait before repeats begin.
interval number 60 Milliseconds between repeats (floored at 16ms).
disabled boolean false Blocks clicks and repeats, and dims the control.
size sm | md | lg md Padding and font size, shared with the rest of the kit.
variant primary | secondary | outline | ghost secondary Visual weight, matching SvButton.
ariaLabel string - Accessible name for icon-only or glyph buttons.
children Snippet - The button label.

Patterns

Number stepper

Pair two repeat buttons around a value so a long press ramps it quickly:

<SvRepeatButton onclick={() => (qty -= 1)} ariaLabel="Decrease">-</SvRepeatButton>
<SvRepeatButton onclick={() => (qty += 1)} ariaLabel="Increase">+</SvRepeatButton>

Faster acceleration

Lower delay and interval for a control that ramps sooner and moves faster, such as a seek or volume button:

<SvRepeatButton delay={200} interval={30} onclick={() => (volume += 1)}>Vol +</SvRepeatButton>

Icon-only

Omit the label and pass ariaLabel so the button still announces:

<SvRepeatButton ariaLabel="Scroll down" variant="ghost" onclick={scrollDown}>▼</SvRepeatButton>

Zoom control with clamping

Because onclick runs on every repeat, clamp the value inside the handler so a long hold stops cleanly at the limits instead of running past them:

<script lang="ts">
  import { SvRepeatButton } from '@svgrid/grid'
  let zoom = $state(100)
  const clamp = (n: number) => Math.min(400, Math.max(25, n))
</script>

<SvRepeatButton variant="outline" ariaLabel="Zoom out" onclick={() => (zoom = clamp(zoom - 5))}>-</SvRepeatButton>
<span>{zoom}%</span>
<SvRepeatButton variant="outline" ariaLabel="Zoom in" onclick={() => (zoom = clamp(zoom + 5))}>+</SvRepeatButton>

Accessibility

See also