Voice input in React & Next.js, done right

Updated July 2026 · by the Sleekio team

Adding a microphone that transcribes speech into a React text field looks trivial and has one sharp edge that trips almost everyone: you can't just setinput.value. Here's why, the correct fix, and a drop-in component if you'd rather skip the whole thing.

Why input.value = text fails in React

React controlled inputs keep their value in state and watch a private value tracker on the DOM node. Assigning element.value directly bypasses that tracker, so your onChange never fires — and on the next render React overwrites your text with its stale state. The dictation appears, then vanishes.

The fix: native setter + synthetic event

Go through the native prototype setter and dispatch a real input event — exactly what a keystroke does under the hood — and React updates correctly:

const proto = el.tagName === "TEXTAREA" ? window.HTMLTextAreaElement.prototype : window.HTMLInputElement.prototype; const setter = Object.getOwnPropertyDescriptor(proto, "value").set; setter.call(el, nextValue); el.dispatchEvent(new Event("input", { bubbles: true }));

Insert at the cursor (selectionStart/selectionEnd) rather than replacing the whole value, so you don't clobber what the user typed.

The drop-in version

The sleekio-widget package does all of this — plus cross-browser audio codecs and the recording UI — behind one component:

npm install sleekio-widget
import { SleekioInput } from "sleekio-widget/react"; function CommentBox() { return ( <SleekioInput apiKey="pk_live_YOURKEY" multiline placeholder="Speak or type a comment…" onResult={(text, meta) => console.log(text, meta.language)} /> ); }

It's SSR-safe (the loader no-ops on the server), so it works in Next.js without hydration errors, and it ships with TypeScript types. Prefer a hook? useSleekio(apiKey) loads it once and decorates every text field on the page.

FAQ

How do I add voice input to a React app?

Install the sleekio-widget package and render a <SleekioInput/> component, or call loadSleekio() once. It inserts transcribed text through a native setter plus a synthetic input event, so your controlled inputs and onChange handlers update correctly — which a plain input.value assignment does not.

Why does setting input.value not work in React?

React controlled inputs track their value in state. Assigning element.value directly bypasses React's value tracker, so onChange never fires and the next render overwrites your text with the old state. The fix is to call the native HTMLInputElement value setter and dispatch a synthetic 'input' event, which React recognizes as a real change.

Does it work with Next.js and server-side rendering?

Yes. The loader is a no-op during SSR and only initializes in the browser, so it works in Next.js, Remix and other SSR frameworks without hydration errors. The <SleekioInput/> component handles this for you.

Is there a TypeScript definition?

Yes — sleekio-widget ships with TypeScript types for both the loader and the React component.

Try it

There's a live demo you can talk into (no signup) on the developer docs, and a free tier with no credit card.

Open the live demo →