feojs
v1.2.0
Published
A React hook that converts speech from the microphone to text and makes it available to your React components
Maintainers
Readme
🎤 Feo (Voice in Malagasy)
A modern, TypeScript-first React hook that converts speech from the microphone to text and makes it available to your React components.
Feo is a spiritual successor to react-speech-recognition, built from the ground up with TypeScript, modern React patterns, and best practices.
Want to know how it works? Well, ask his parent directly react-speech-recognition by James Brill
✨ Features
- 🎯 TypeScript First: Fully typed API with excellent IntelliSense support
- 🪝 Modern React: Built with hooks and functional components
- 🌐 Cross-browser: Supports polyfills for enhanced browser compatibility
- 🎛️ Command Recognition: Sophisticated command matching with fuzzy search
- 🔧 Configurable: Extensive customization options
- 🧪 Well Tested: Comprehensive test coverage with Vitest
- ⚡ Lightweight: Minimal bundle size with tree-shaking support
- 🔄 Continuous Listening: Support for continuous speech recognition
📦 Installation
npm install feojsyarn add feojspnpm add feojs🚀 Quick Start
import React from 'react'
import SpeechRecognition, { useSpeechRecognition } from 'feojs'
const VoiceRecorder = () => {
const {
transcript,
listening,
resetTranscript,
browserSupportsSpeechRecognition
} = useSpeechRecognition()
if (!browserSupportsSpeechRecognition) {
return <span>Browser doesn't support speech recognition.</span>
}
return (
<div>
<p>Microphone: {listening ? 'on' : 'off'}</p>
<button onClick={() => SpeechRecognition.startListening()}>Start</button>
<button onClick={SpeechRecognition.stopListening}>Stop</button>
<button onClick={resetTranscript}>Reset</button>
<p>{transcript}</p>
</div>
)
}
export default VoiceRecorder🎯 Voice Commands
Feo supports sophisticated voice command recognition with pattern matching:
import React, { useState } from 'react'
import SpeechRecognition, { useSpeechRecognition } from 'feojs'
const VoiceAssistant = () => {
const [message, setMessage] = useState('')
const commands = [
{
command: 'I would like to order *',
callback: (food: string) => setMessage(`Your order is for: ${food}`)
},
{
command: 'The weather is :condition today',
callback: (condition: string) => setMessage(`Today, the weather is ${condition}`)
},
{
command: 'My top sports are * and *',
callback: (sport1: string, sport2: string) => setMessage(`#1: ${sport1}, #2: ${sport2}`)
},
{
command: 'Pass the salt (please)',
callback: () => setMessage('My pleasure')
},
{
command: ['Hello', 'Hi'],
callback: ({ command }: { command: string }) => setMessage(`Hi there! You said: "${command}"`),
matchInterim: true
},
{
command: 'clear',
callback: ({ resetTranscript }: { resetTranscript: () => void }) => {
resetTranscript()
setMessage('')
}
}
]
const {
transcript,
listening,
resetTranscript,
browserSupportsSpeechRecognition
} = useSpeechRecognition({ commands })
const startListening = () => SpeechRecognition.startListening({
continuous: true,
language: 'en-US'
})
if (!browserSupportsSpeechRecognition) {
return <span>Browser doesn't support speech recognition.</span>
}
return (
<div>
<p>Microphone: {listening ? 'on' : 'off'}</p>
<button onClick={startListening}>Start Listening</button>
<button onClick={SpeechRecognition.stopListening}>Stop</button>
<button onClick={resetTranscript}>Reset</button>
<p><strong>Transcript:</strong> {transcript}</p>
{message && <p><strong>Response:</strong> {message}</p>}
</div>
)
}
export default VoiceAssistant📚 API Reference
useSpeechRecognition(options?)
React hook that provides speech recognition state and controls.
Options
interface SpeechRecognitionHookOptions {
transcribing?: boolean // Whether to update transcript state (default: true)
clearTranscriptOnListen?: boolean // Whether to clear transcript when starting (default: true)
commands?: SpeechRecognitionCommand[] // Array of voice commands
}Returns
interface SpeechRecognitionHookState {
transcript: string // Complete transcript
interimTranscript: string // Interim (incomplete) transcript
finalTranscript: string // Final (complete) transcript
listening: boolean // Whether currently listening
isMicrophoneAvailable: boolean // Whether microphone is available
resetTranscript: () => void // Function to reset transcript
browserSupportsSpeechRecognition: boolean // Whether browser supports speech recognition
browserSupportsContinuousListening: boolean // Whether browser supports continuous listening
}📄 License
MIT
🙏 Acknowledgments
- Inspired by react-speech-recognition by James Brill
- Built with Vite and TypeScript
- Tested with Vitest and Testing Library
🛠️ Development
Automated Release Scripts
This project includes automated scripts for version bumping and releasing:
# Preview what would be released (dry run)
npm run push:dry
# Standard release (with confirmation)
npm run push
# Force release (skip confirmations)
npm run push:forceThe scripts automatically:
- Analyze git commits since the last tag
- Determine version bump type (major/minor/patch) based on conventional commits
- Update package.json version
- Run tests and build the project
- Create git commit and tag
- Push changes to remote repository
See scripts/README.md for detailed documentation.
Manual Development
# Start development server
npm run dev
# Run tests
npm test
# Run tests in watch mode
npm run test:watch
# Build the library
npm run build
# Lint code
npm run lint
# Type check
npm run build:typesMade with ❤️ for the React community
You can also install eslint-plugin-react-x and eslint-plugin-react-dom for React-specific lint rules:
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'
export default tseslint.config([
globalIgnores(['dist']),
{
files: ['**/*.{ts,tsx}'],
extends: [
// Other configs...
// Enable lint rules for React
reactX.configs['recommended-typescript'],
// Enable lint rules for React DOM
reactDom.configs.recommended,
],
languageOptions: {
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
// other options...
},
},
])