DEV Community

VoiceDeveloper
VoiceDeveloper

Posted on

ElevenLabs + React: Building a Voice-Enabled UI

Why Voice‑First UI Matters Today

If you’ve been watching the rise of voice assistants, you’ve probably noticed a shift from “nice‑to‑have” to “must‑have.” Users expect apps to respond instantly, and hearing a natural‑sounding voice can make a UI feel more personal, accessible, and engaging.

Enter ElevenLabs, a text‑to‑speech (TTS) platform that delivers ultra‑realistic voices and even lets you clone your own. The service is API‑first, which means you can drop it into any front‑end stack—React included—without wrestling with heavy SDKs or on‑prem models.

In this post I’ll walk you through wiring up a simple voice‑enabled React component that:

  1. Sends user‑typed text to ElevenLabs.
  2. Streams the generated audio back to the browser.
  3. Handles playback controls so the UI feels snappy.

All of this can be done with a handful of lines of JavaScript and a free ElevenLabs account (sign up via my affiliate link: https://try.elevenlabs.io/kr07zfuqn1bp).


Getting Started: Prerequisites

  • Node.js (v16+ recommended)
  • Create‑React‑App or any React starter of your choice
  • An ElevenLabs API key (grab it from the dashboard after signing up)

Pro tip: If you want to experiment with voice cloning, upload a short sample of your own voice in the ElevenLabs console. The cloned voice works the same way as the built‑in models.


Step 1 – Set Up the React Project

npx create-react-app voice-ui-demo
cd voice-ui-demo
npm install axios
Enter fullscreen mode Exit fullscreen mode

We’ll use axios for HTTP requests because it handles streaming responses nicely, but fetch works just as well.


Step 2 – Create a Tiny API Wrapper

Create a new file src/elevenlabs.js:

// src/elevenlabs.js
import axios from "axios";

const API_KEY = process.env.REACT_APP_ELEVENLABS_API_KEY;
const BASE_URL = "https://api.elevenlabs.io/v1";

export const generateSpeech = async (text, voiceId = "EXAVITQu4vr4xnGd") => {
  const response = await axios({
    method: "post",
    url: `${BASE_URL}/text-to-speech/${voiceId}`,
    headers: {
      "xi-api-key": API_KEY,
      "Content-Type": "application/json",
      Accept: "audio/mpeg",
    },
    data: {
      text,
      // optional: voice settings like stability & similarity_boost
      voice_settings: { stability: 0.75, similarity_boost: 0.85 },
    },
    responseType: "blob", // we want raw audio data
  });

  return URL.createObjectURL(response.data);
};
Enter fullscreen mode Exit fullscreen mode

Note: Replace REACT_APP_ELEVENLABS_API_KEY in your .env file with the key you got from ElevenLabs (https://try.elevenlabs.io/kr07zfuqn1bp). React will automatically inject it at build time.


Step 3 – Build the UI Component

// src/components/VoiceInput.jsx
import { useState } from "react";
import { generateSpeech } from "../elevenlabs";

export default function VoiceInput() {
  const [text, setText] = useState("");
  const [audioUrl, setAudioUrl] = useState(null);
  const [loading, setLoading] = useState(false);

  const handleSpeak = async () => {
    if (!text.trim()) return;
    setLoading(true);
    try {
      const url = await generateSpeech(text);
      setAudioUrl(url);
    } catch (err) {
      console.error("TTS error:", err);
    } finally {
      setLoading(false);
    }
  };

  return (
    <div style={{ maxWidth: "480px", margin: "auto", padding: "1rem" }}>
      <h2>🗣️ Talk to Your App</h2>
      <textarea
        rows={4}
        placeholder="Type something…"
        value={text}
        onChange={(e) => setText(e.target.value)}
        style={{ width: "100%", marginBottom: "0.5rem" }}
      />
      <button onClick={handleSpeak} disabled={loading}>
        {loading ? "Generating…" : "Speak"}
      </button>

      {audioUrl && (
        <div style={{ marginTop: "1rem" }}>
          <audio controls src={audioUrl} />
        </div>
      )}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Add the component to App.js:

import VoiceInput from "./components/VoiceInput";

function App() {
  return (
    <div className="App">
      <VoiceInput />
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

That’s it—type a sentence, hit Speak, and you’ll hear a high‑fidelity voice rendered by ElevenLabs.


Step 4 – Streaming (Optional, but Cool)

If you want to start playback before the whole file finishes downloading, you can switch the Axios call to a ReadableStream. Here’s a quick sketch:

export const streamSpeech = async (text, voiceId = "EXAVITQu4vr4xnGd") => {
  const response = await fetch(`${BASE_URL}/text-to-speech/${voiceId}`, {
    method: "POST",
    headers: {
      "xi-api-key": API_KEY,
      "Content-Type": "application/json",
      Accept: "audio/mpeg",
    },
    body: JSON.stringify({ text, voice_settings: { stability: 0.75 } }),
  });

  const reader = response.body.getReader();
  const chunks = [];

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    chunks.push(value);
  }

  const blob = new Blob(chunks, { type: "audio/mpeg" });
  return URL.createObjectURL(blob);
};
Enter fullscreen mode Exit fullscreen mode

Swap generateSpeech with streamSpeech in the component and you’ll notice the audio starts playing almost instantly—a nice UX win for longer passages.


Real‑World Use Cases

Scenario How ElevenLabs Helps
Accessibility Convert UI text, error messages, or form hints into speech for screen‑reader‑free experiences.
Interactive Games NPCs can speak dynamically generated dialogue without pre‑recorded assets.
Customer Support Bots Pair a chat‑bot with a voice channel for a truly omnichannel feel.
Personalized Assistants Clone a brand’s voice (or your own) and keep the tone consistent across all touchpoints.

Because the API is stateless, you can spin up a micro‑service that handles TTS for multiple front‑ends—React, Flutter, or even a simple curl script.


Quick curl Demo

If you just want to test the endpoint without writing code:

curl -X POST "https://api.elevenlabs.io/v1/text-to-speech/EXAVITQu4vr4xnGd" \
  -H "xi-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: audio/mpeg" \
  -d '{"text":"Hello from ElevenLabs!", "voice_settings":{"stability":0.7}}' \
  --output hello.mp3
Enter fullscreen mode Exit fullscreen mode

Open hello.mp3 and you’ll hear the same voice that powered your React component.


Handling Rate Limits & Costs

ElevenLabs offers a generous free tier (up to 10 k characters per month). After that, pricing is pay‑as‑you‑go, and the API returns 429 Too Many Requests when you exceed your quota. A simple exponential back‑off or a client‑side queue can keep the UI smooth:

const delay = (ms) => new Promise((res) => setTimeout(res, ms));

async function safeGenerate(text) {
  let attempts = 0;
  while (attempts < 5) {
    try {
      return await generateSpeech(text);
    } catch (err) {
      if (err.response?.status === 429) {
        await delay(2 ** attempts * 500); // back‑off
        attempts++;
      } else {
        throw err;
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Wrapping Up

Building a voice‑enabled UI in React is surprisingly straightforward when you have a solid TTS backend. ElevenLabs provides:

  • Natural‑sounding voices that rival commercial assistants.
  • Voice cloning for brand consistency or personal flair.
  • Simple REST API that works across any language or framework.

Give it a spin, experiment with different voice settings, and watch how quickly your app feels more alive.

Ready to add a human touch to your next project? Grab an API key and start generating speech right now: https://try.elevenlabs.io/kr07zfuqn1bp. Happy coding!

Top comments (0)