Home / Blog / Give Your Web Apps a Voice with Eleven Labs AI
Give Your Web Apps a Voice with Eleven Labs AI

Give Your Web Apps a Voice with Eleven Labs AI

Daniel Kelly
Daniel Kelly
Updated: March 24th 2025

I started this blog post experimenting with Eleven Labs to turn text into speech within the context of a Vue project. What I ended up with was a Nuxt layer for turning Nuxt content markdown files into realistic sounding speech.

Say hello to Nuxt Content Narrator, a powerful new layer for Nuxt Content that brings text-to-speech capabilities to your content pages. This solution seamlessly integrates Nuxt Content with Eleven Labs’ state-of-the-art voice synthesis technology to create natural, engaging audio versions of your Markdown content.

Nuxt Content Narrator Key Features

  1. Zero config Nuxt Content text to speech with Eleven labs
  2. Audio player with progress indicator and playback control
  3. Synchronized text highlighting during playback (optional)
  4. Easy to use components with customization options

Get Started Adding Text-To-Speech Capabilities to Nuxt Content

Getting up and running with Nuxt Content Narrator is straightforward. Here’s how to add narration capabilities to your Nuxt Content site:

1. Installation

First, install the layer using npm:

npm i nuxt-content-narrator

Then extend it in your Nuxt configuration:

// nuxt.config.ts
extends: ["nuxt-content-narrator"],

2. Eleven Labs API Key Setup

You’ll need an ElevenLabs API key to generate the voice narration. Once you have your key from ElevenLabs, set it as an environment variable. (Note: Eleven Labs is a premium product and the cost of generating audio will increase as the size of the content increases.)

NUXT_ELEVENLABS_API_KEY=sk_xxx

3. Use Nuxt Content Narrator Components on Content Pages

The narrator system consists of several components that work together to provide a complete text-to-speech solution. Included components are:

  • NcNarratorService: The main component that manages text-to-speech functionality
  • NcNarratorPlayer: A customizable audio player with playback controls
  • NcNarratorFollowAlongRenderer: Provides synchronized text highlighting
  • NcNarratorDevTools: Development tools for audio generation

Here’s a basic implementation example:

<script setup lang="ts">
const route = useRoute();

// fetch your content using Nuxt Content's built in queryCollection function
const { data: story } = await useAsyncData(() =>
  queryCollection("stories")
    .path(route.path.toString() ?? "")
    .first()
);
</script>

<template>
  <article class="prose prose-lg mx-auto">
   <!-- Wrap the content in the NcNarratorService -->
    <NcNarratorService
      v-if="story"
      :collection-item="story"
      voiceId="FGY2WhTYpPnrIDTdsKH5"
    >
      <!--Display the player-->
      <NcNarratorPlayer progressClass="bg-gray-900" />

      <!--Display a button to generate audio in development-->
      <NcNarratorDevTools />

      <!--
      Optionally use the Follow Along Renderer for synchronized text 
      highlighting. If no highlighting is needed use the 
      normal <ContentRenderer/>
      -->
      <NcNarratorFollowAlongRenderer
        highlightClass="bg-gray-900"
        highlightTextClass="text-white"
      />
    </NcNarratorService>
  </article>
</template>

4. Generate the Audio for Your Content

Once you’ve got the components setup on a content page you should use the button provided by the NcNarratorDevtools to generate the audio for the current page content.

If no audio is found, playing the audio for the first time will generate it on the fly (which will take a little time depending on the content length) but if you want to update the audio because you’ve updated a post, you’ll need to force generate it with this button.

By default generated audio is stored in a directory named audio at the project root along with timings. You should generate audio on your local machine in development and then save it to the github repo.

Alternately, you can store audio to other storage services like an Amazon s3 bucket or Netlify blobs with a custom nitro storage configuration:

// nuxt.config.ts
nitro: {
    devStorage: {
      audio: {
        driver: "[your choice]", // https://unstorage.unjs.io/drivers
      },
    },
  },

Customize the Nuxt Content Narrator Voice

To customize the voice used for narration you can pass in a voiceId to the NcNarratorService component. This means you can hardcode the voice id for a consistent feel throughout your site or provide it dynamically to customize the voice per page.

You can browse the voices available on the Elevenlabs website and snag the id from the url by clicking the “View” button on the desired voice.

Browse Eleven Labs voices on their website and pick the id of the voice that best fits your needs

Browse Eleven Labs voices on their website and pick the id of the voice that best fits your needs

Customize the Player with a Vue Slot

If the style of the built-in player doesn’t fit your needs, you can customize the rendering 100% with it’s default slot.

<NcNarratorPlayer
  v-slot="{ 
    play, // function to play the audio
    pause, // function to pause the audio
    toggle, // function to toggle the audio
    playing, // boolean to check if the audio is playing
    currentTime, // number to get the current time of the audio
    duration, // number to get the duration of the audio
    percentComplete // number to get the percent complete of the audio
  }"
>
  <!-- Your custom player UI -->
</NcNarratorPlayer>

Let User’s Follow Along with the Audio with Text Synchronization

The synchronized text feature allows the user to follow along with the audio and can handle many different formats like headings, lists, code, bold, italic, etc. Below is a demonstration of how it works.

As you can tell, right now the list handling could use a little more work to make it sound more natural and code blocks are simply skipped in narration but otherwise the various content types have pretty good support!

Conclusion

Nuxt Content Narrator brings a new dimension to your content by making it accessible through high-quality voice narration with very little effort. Whether you’re building a blog, documentation site, or any content-rich application, this layer makes it easy to add professional text-to-speech capabilities to your Nuxt Content pages.

Related Courses

Start learning Vue.js for free

Daniel Kelly
Daniel Kelly
Daniel is the lead instructor at Vue School and enjoys helping other developers reach their full potential. He has 10+ years of developer experience using technologies including Vue.js, Nuxt.js, and Laravel.

Comments

Latest Vue School Articles

What is a Vue.js Error Boundary Component?

What is a Vue.js Error Boundary Component?

Error boundaries in Vue are a game-changing tool that prevents your entire application from crashing when a component fails, ensuring a smooth user experience. In this guide, we'll explore how error boundaries work, how to implement them in your Vue applications, and where to find pre-built solutions to save you time.
Daniel Kelly
Daniel Kelly
Form and Function with Formwerk &#8211; Insights from Abdelrahman Awad’s Vue.js Nation 2025 Talk

Form and Function with Formwerk – Insights from Abdelrahman Awad’s Vue.js Nation 2025 Talk

Formwork, a flexible Vue.js library for accessible, customizable forms with seamless integration and robust validation by Abdelrahman Awad at Vue.js Nation 2025
Eleftheria Batsou
Eleftheria Batsou

Our goal is to be the number one source of Vue.js knowledge for all skill levels. We offer the knowledge of our industry leaders through awesome video courses for a ridiculously low price.

More than 200.000 users have already joined us. You are welcome too!

Follow us on Social

© All rights reserved. Made with ❤️ by BitterBrains, Inc.