Skip to content

Sound & Feedback

onStep fires only when the value crosses from one step tick to another — not on every pixel of drag. This makes it ideal for audio or haptic feedback without overwhelming the output.

<FractionalRange
min={0}
max={2}
step={0.1}
onStep={(value) => {
console.log('Crossed to', value)
}}
/>
CallbackFires whenUse case
onChangeEvery value update during dragUpdating UI, syncing state
onStepValue crosses to a different step tickSound, haptics, discrete feedback

For production audio, use a library like Howler.js which handles audio pooling and prevents channel stacking:

Terminal window
npm install howler
import { Howl } from 'howler'
// Create the sound once, outside the component
const tick = new Howl({
src: ['/tick.mp3'],
volume: 0.3,
pool: 5, // Allow up to 5 simultaneous plays
})
function MySlider() {
return (
<FractionalRange
min={0}
max={2}
step={0.1}
onStep={() => tick.play()}
/>
)
}

For basic use cases, the Web Audio API works without extra dependencies:

function MySlider() {
const playTick = () => {
try {
new Audio('/tick.mp3').play()
} catch {
// Audio not available
}
}
return (
<FractionalRange
min={0}
max={2}
step={0.1}
onStep={playTick}
/>
)
}

On supported devices, you can trigger haptic feedback:

<FractionalRange
min={0}
max={1}
step={0.1}
onStep={() => {
navigator.vibrate?.(5)
}}
/>