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
- Renders a native
<button type="button">, so focus andTaborder are the browser's own. EnterandSpacefireonclickonce (key auto-repeat is ignored); the press-and-hold acceleration is a pointer gesture.- Releasing the pointer anywhere, leaving the button, or a pointer cancel all stop the repeat, so it can never run away.
- Icon-only buttons must set
ariaLabel.
See also
- SvButton - the base button this shares its look with.
- SvButtonGroup - a segmented set of buttons.
- Buttons & toggles overview - the whole family at a glance.