npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-voice-to-text-converter

v1.0.3

Published

> A powerful React hook for seamless speech-to-text conversion with real-time transcription, multi-language support, and automatic punctuation.

Readme

react-voice-to-text-converter

A powerful React hook for seamless speech-to-text conversion with real-time transcription, multi-language support, and automatic punctuation.

npm version License: MIT React

✨ Features

  • 🎤 Real-time Speech Recognition - Live transcription as you speak
  • 🌍 Multi-language Support - 12+ languages including English, Spanish, Hindi, Chinese, and more
  • 📝 Automatic Punctuation - Voice commands for commas, periods, question marks, etc.
  • 🔢 Smart Number Conversion - Converts spoken numbers to digits automatically
  • 📋 Append to Existing Text - Preserve and build upon existing content
  • Continuous Recording - No interruptions during speech
  • 🎯 TypeScript Ready - Full type definitions included
  • 🚀 Zero Dependencies - Built on native Web Speech API
  • 📱 Mobile Friendly - Works on iOS Safari and Android Chrome

📦 Installation

npm install react-voice-to-text-converter

or

yarn add react-voice-to-text-converter

🚀 Quick Start

import React, { useState, useCallback } from 'react';
import { useVoiceInput } from 'react-voice-to-text-converter';

function App() {
  const [text, setText] = useState('');

  const handleTranscript = useCallback((transcript, isFinal) => {
    setText(transcript);
  }, []);

  const { isListening, toggleListening, isSupported } = useVoiceInput({
    onTranscript: handleTranscript,
    language: 'en-US'
  });

  if (!isSupported) {
    return <div>Voice input not supported. Use Chrome, Edge, or Safari.</div>;
  }

  return (
    <div>
      <textarea value={text} onChange={(e) => setText(e.target.value)} />
      <button onClick={toggleListening}>
        {isListening ? '🛑 Stop' : '🎤 Start'} Recording
      </button>
    </div>
  );
}

📖 Documentation

API Reference

Parameters

useVoiceInput({
  onTranscript: (text: string, isFinal: boolean) => void,
  language?: string,        // Default: 'en-US'
  disabled?: boolean        // Default: false
})

| Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | onTranscript | (text: string, isFinal: boolean) => void | ✅ | - | Callback fired when transcript updates | | language | string | ❌ | 'en-US' | Language code for recognition | | disabled | boolean | ❌ | false | Disable voice input functionality |

Return Values

{
  isListening: boolean;
  isSupported: boolean;
  error: string | null;
  startListening: () => void;
  stopListening: () => void;
  toggleListening: () => void;
  clearTranscript: () => void;
  setBaseText: (text: string) => void;
}

| Property | Type | Description | |----------|------|-------------| | isListening | boolean | true when actively recording | | isSupported | boolean | true if browser supports Web Speech API | | error | string \| null | Error message if recognition fails | | startListening | function | Start voice recognition | | stopListening | function | Stop voice recognition | | toggleListening | function | Toggle recording on/off | | clearTranscript | function | Clear transcript and stop recording | | setBaseText | function | Set existing text to append new speech to |

🌍 Supported Languages

const languages = [
  'en-US',  // English (US)
  'en-GB',  // English (UK)
  'es-ES',  // Spanish
  'fr-FR',  // French
  'de-DE',  // German
  'it-IT',  // Italian
  'pt-BR',  // Portuguese
  'hi-IN',  // Hindi
  'zh-CN',  // Chinese
  'ja-JP',  // Japanese
  'ko-KR',  // Korean
  'ar-SA'   // Arabic
];

🎯 Voice Commands

The hook automatically recognizes voice commands for punctuation:

| Voice Command | Result | Example | |---------------|--------|---------| | "comma" | , | "Hello comma world" → "Hello, world" | | "full stop" / "period" | . | "Hello full stop" → "Hello." | | "question mark" | ? | "How are you question mark" → "How are you?" | | "exclamation mark" | ! | "Wow exclamation mark" → "Wow!" | | "colon" | : | "Note colon" → "Note:" | | "semicolon" | ; | "First semicolon" → "First;" | | "next line" / "new line" | \n | Line break |

Number Conversion:

  • "three apples" → "3 apples"
  • "one hundred" → "100"
  • "one thousand" → "1000"

💡 Usage Examples

Example 1: Basic Text Input

function VoiceTextInput() {
  const [text, setText] = useState('');

  const { isListening, toggleListening } = useVoiceInput({
    onTranscript: (transcript) => setText(transcript),
    language: 'en-US'
  });

  return (
    <div>
      <textarea 
        value={text} 
        onChange={(e) => setText(e.target.value)}
        rows={10}
      />
      <button onClick={toggleListening}>
        {isListening ? '🛑 Stop' : '🎤 Start'}
      </button>
    </div>
  );
}

Example 2: Append to Existing Text

function AppendVoice() {
  const [content, setContent] = useState('Existing content here. ');

  const { isListening, toggleListening, setBaseText } = useVoiceInput({
    onTranscript: (transcript) => setContent(transcript)
  });

  const handleToggle = () => {
    if (!isListening) {
      // Preserve existing content
      setBaseText(content);
    }
    toggleListening();
  };

  return (
    <div>
      <textarea value={content} onChange={(e) => setContent(e.target.value)} />
      <button onClick={handleToggle}>
        {isListening ? 'Stop' : 'Append Voice'}
      </button>
    </div>
  );
}

Example 3: Multi-language Support

function MultiLanguageVoice() {
  const [text, setText] = useState('');
  const [language, setLanguage] = useState('en-US');

  const { isListening, toggleListening } = useVoiceInput({
    onTranscript: (transcript) => setText(transcript),
    language: language
  });

  return (
    <div>
      <select value={language} onChange={(e) => setLanguage(e.target.value)}>
        <option value="en-US">English (US)</option>
        <option value="es-ES">Spanish</option>
        <option value="hi-IN">Hindi</option>
        <option value="zh-CN">Chinese</option>
      </select>
      
      <textarea value={text} onChange={(e) => setText(e.target.value)} />
      <button onClick={toggleListening}>
        {isListening ? 'Stop' : 'Start'}
      </button>
    </div>
  );
}

Example 4: With Error Handling

function RobustVoiceInput() {
  const [text, setText] = useState('');

  const { 
    isListening, 
    isSupported, 
    error, 
    toggleListening 
  } = useVoiceInput({
    onTranscript: (transcript) => setText(transcript)
  });

  if (!isSupported) {
    return (
      <div className="error">
        ⚠️ Voice input not supported. Please use Chrome, Edge, or Safari.
      </div>
    );
  }

  return (
    <div>
      {error && (
        <div className="error">
          Error: {error}
          {error.includes('denied') && (
            <div>Please allow microphone access in browser settings.</div>
          )}
        </div>
      )}
      
      <textarea value={text} onChange={(e) => setText(e.target.value)} />
      <button onClick={toggleListening}>
        {isListening ? 'Stop' : 'Start'}
      </button>
    </div>
  );
}

Example 5: ContentEditable Integration

function EditableVoiceInput() {
  const [content, setContent] = useState('');
  const contentRef = useRef(null);

  const { isListening, toggleListening, setBaseText } = useVoiceInput({
    onTranscript: (text) => {
      if (contentRef.current) {
        contentRef.current.innerHTML = text.replace(/\n/g, '<br>');
      }
      setContent(text);
    }
  });

  const handleToggle = () => {
    if (!isListening) {
      setBaseText(contentRef.current?.textContent || '');
    }
    toggleListening();
  };

  return (
    <div>
      <div
        ref={contentRef}
        contentEditable
        suppressContentEditableWarning
        style={{ 
          border: isListening ? '2px solid red' : '1px solid gray',
          padding: '10px',
          minHeight: '100px'
        }}
      >
        {content}
      </div>
      <button onClick={handleToggle}>
        {isListening ? 'Stop' : 'Start'}
      </button>
    </div>
  );
}

🎨 Real-World Example

Here's a complete example with all features:

import React, { useState, useCallback, useRef } from 'react';
import { useVoiceInput } from 'react-voice-to-text-converter';

export default function VoiceEditor() {
  const [content, setContent] = useState('');
  const contentRef = useRef(null);

  const handleVoiceTranscript = useCallback((text, isFinal) => {
    // Update DOM for real-time feel
    if (contentRef.current) {
      contentRef.current.textContent = text;
    }
    setContent(text);

    // Auto-save on final
    if (isFinal) {
      console.log('Saved:', text);
    }
  }, []);

  const {
    isListening,
    isSupported,
    error,
    toggleListening,
    setBaseText
  } = useVoiceInput({
    onTranscript: handleVoiceTranscript,
    language: 'en-US'
  });

  const handleToggleVoice = () => {
    if (!isListening) {
      setBaseText(contentRef.current?.textContent || '');
    }
    toggleListening();
  };

  if (!isSupported) {
    return <div>Voice input not supported. Use Chrome, Edge, or Safari.</div>;
  }

  return (
    <div style={{ padding: '20px', maxWidth: '800px', margin: '0 auto' }}>
      <h2>Voice-Enabled Text Editor</h2>

      {error && (
        <div style={{ 
          padding: '10px', 
          backgroundColor: '#f8d7da', 
          marginBottom: '10px' 
        }}>
          Error: {error}
        </div>
      )}

      <div
        ref={contentRef}
        contentEditable
        suppressContentEditableWarning
        onInput={(e) => {
          if (!isListening) {
            setContent(e.currentTarget.textContent);
          }
        }}
        style={{
          border: `2px solid ${isListening ? '#dc3545' : '#ced4da'}`,
          padding: '15px',
          minHeight: '200px',
          marginBottom: '10px',
          backgroundColor: isListening ? '#fff5f5' : 'white'
        }}
      >
        {content}
      </div>

      <button
        onClick={handleToggleVoice}
        style={{
          padding: '10px 20px',
          backgroundColor: isListening ? '#dc3545' : '#007bff',
          color: 'white',
          border: 'none',
          borderRadius: '4px',
          cursor: 'pointer'
        }}
      >
        {isListening ? '🛑 Stop Recording' : '🎤 Start Voice Input'}
      </button>

      {isListening && (
        <span style={{ marginLeft: '10px', color: '#dc3545' }}>
          🎤 Recording...
        </span>
      )}
    </div>
  );
}

🌐 Browser Support

| Browser | Support | Notes | |---------|---------|-------| | Chrome | ✅ Full Support | Recommended | | Edge | ✅ Full Support | Chromium-based | | Safari | ✅ Full Support | iOS 14.5+ | | Firefox | ⚠️ Limited | Requires flag enabled | | Opera | ✅ Full Support | Chromium-based |

Note: Always check the isSupported property before rendering voice controls.

⚙️ Best Practices

1. Always Check Browser Support

const { isSupported } = useVoiceInput({ onTranscript: handleTranscript });

if (!isSupported) {
  return <div>Please use Chrome, Edge, or Safari</div>;
}

2. Use useCallback for onTranscript

// ✅ Good - Prevents unnecessary re-renders
const handleTranscript = useCallback((text, isFinal) => {
  setText(text);
}, []);

// ❌ Bad - Creates new function every render
const handleTranscript = (text, isFinal) => {
  setText(text);
};

3. Set Base Text Before Recording

const handleStartRecording = () => {
  if (!isListening) {
    setBaseText(existingContent); // Set BEFORE toggle
  }
  toggleListening();
};

4. Handle Errors Gracefully

{error && (
  <div className="error">
    {error}
    {error.includes('denied') && (
      <div>Please allow microphone access</div>
    )}
  </div>
)}

5. Prevent Manual Input During Recording

<textarea
  value={content}
  onChange={(e) => {
    if (!isListening) { // Only when not recording
      setContent(e.target.value);
    }
  }}
/>

🐛 Troubleshooting

"Microphone access denied"

Solution:

  1. Click the microphone icon in browser address bar
  2. Select "Always allow" for your site
  3. Reload the page

Voice input not working

Check:

  • Browser compatibility (use Chrome/Edge/Safari)
  • Microphone permissions
  • HTTPS connection (required for Web Speech API)
  • Check error state for specific error messages

Base text not preserved

Solution: Call setBaseText() BEFORE toggleListening():

// ✅ Correct
setBaseText(existingText);
toggleListening();

// ❌ Wrong
toggleListening();
setBaseText(existingText); // Too late!

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📄 License

MIT © Abhishek MS

📞 Support

For issues, questions, or contributions:

🙏 Acknowledgments

Built with the Web Speech API and lots of ☕


Made with ❤️ by Abhishek MS

Star on GitHub