Build a Real-time Speech Recognition Search Box with Next.js and Tailwind CSS
Building a real-time speech recognition search box using Next.js, Tailwind CSS, and the react-speech-recognition library
Let's build a real-time speech recognition search box using Next.js and Tailwind CSS. We'll leverage the react-speech-recognition
library for managing speech recognition. This guide will cover setting up the project, writing the code, and understanding the logic behind it.
Prerequisites
Before you begin, ensure you have the following:
- Node.js installed
- npm or yarn as your package manager
- Basic knowledge of React
- Familiarity with Tailwind CSS
Step 1: Set Up the Project
Create a new Next.js project:
npx create-next-app@latest speech-recognition-search-box
cd speech-recognition-search-box
Install necessary dependencies:
npm install react-speech-recognition @mui/icons-material react-icons
Set up Tailwind CSS:
npm install -D tailwindcss postcss autoprefixer npx tailwindcss init -p
Configure tailwind.config.js
:
module.exports = {
content: [
'./pages/**/*.{js,ts,jsx,tsx}',
'./components/**/*.{js,ts,jsx,tsx}',
],
theme: {
extend: {},
},
plugins: [],
};
Create styles/globals.css
:
@tailwind base;
@tailwind components;
@tailwind utilities;
Step 2: Create the Search Box Component
Create components/SearchBox.js
:
'use client';
import React, { useState, useEffect, useRef } from'react';
import SearchIcon from '@mui/icons-material/Search';
import Mic from '@mui/icons-material/Mic';
import { RiEqualizerLine } from'react-icons/ri';
import SpeechRecognition, { useSpeechRecognition } from'react-speech-recognition';
This part imports necessary libraries and components:
- React for creating the component.
- useState, useEffect, useRef hooks from React for managing component state and lifecycle.
- SearchIcon, Mic from Material-UI for icons.
- RiEqualizerLine from
react-icons
for another icon. - SpeechRecognition, useSpeechRecognition from
react-speech-recognition
for managing speech recognition.
Define the Icon
component:
const Icon = ({ children, onClick, ariaLabel, className }) => (
<div onClick={onClick} aria-label={ariaLabel} className={`cursor-pointer ${className}`}>
{children}
</div>
);
This component renders an icon with common styles and behavior. It accepts:
children
: The icon component to render.onClick
: Click event handler.ariaLabel
: Accessibility label.className
: Additional CSS classes.
Define the SearchBox
component:
export const SearchBox = () => {
const [isModalOpen, setIsModalOpen] = useState(false);
const [inputValue, setInputValue] = useState('');
const { transcript, listening, resetTranscript } = useSpeechRecognition();
const timeoutRef = useRef(null);
const startListening = () => {
resetTranscript();
SpeechRecognition.startListening({ continuous: true });
setIsModalOpen(true);
resetTimeout();
};
const stopListening = () => {
SpeechRecognition.stopListening();
setIsModalOpen(false);
clearTimeout(timeoutRef.current);
};
const handleMicClick = () => {
if (listening) {
stopListening();
} else {
startListening();
}
};
const handleCloseModal = () => {
stopListening();
};
const handleInputChange = (event) => {
setInputValue(event.target.value);
};
const resetTimeout = () => {
clearTimeout(timeoutRef.current);
if (listening) {
stopListening();
}, [transcript]);
useEffect(() => {
if (!isModalOpen && transcript) {
setInputValue(transcript.trim());
resetTranscript();
}, [isModalOpen, transcript, resetTranscript]);
if (!SpeechRecognition.browserSupportsSpeechRecognition()) {
return <span>Browser doesn't support speech recognition.</span>;
};
This checks if the browser supports speech recognition and displays a message if it doesn't.
Render the component:
<div>
<div className="flex text-center w-full max-w-80 items-center border dark:border-none dark:bg-slate-700 shadow-slate-400 bg-slate-700 p-6 rounded-full px-4 py-1 mr-1 mr-2 mb-4 bg-green-500 animate-pulse' : ''});
This code renders the search box and modal:
- Search Icon: Opens the modal and starts listening.
- Microphone Icon: Toggles speech recognition.
- Filter Icon: Placeholder for additional functionality.
Handle unsupported browsers:
if (!SpeechRecognition.browserSupportsSpeechRecognition()) {
return <span>Browser doesn't support speech recognition.</span>;
}
This checks if the browser supports speech recognition and displays a message if it doesn't.
Render the component:
return (
<div>
<div className="flex text-center w-full max-w-80 items-center border dark:border-none dark:bg-slate-700 shadow-slate-400 bg-slate-100 rounded-full px-4 py-1">
<Icon onClick={handleMicClick} ariaLabel={'Search icon'} className="text-gray-400 mr-2">
<SearchIcon />
</Icon>
<input
type="text"
placeholder="Search"
value={inputValue}
onChange={handleInputChange}
className="outline-none bg-transparent text-gray-700 dark:text-gray-200 w-full"
/>
<Icon onClick={handleMicClick} ariaLabel={'Microphone icon'} className="text-gray-400 mr-1">
<Mic />
</Icon>
<Icon onClick={handleMicClick} ariaLabel={'Filter icon'} className="text-gray-400 mr-1">
<RiEqualizerLine />
</Icon>
</div>
{isModalOpen && (
<div className="fixed inset-0 flex items-center justify-center z-50">
<div className="bg-white dark:bg-slate-700 p-6 rounded-lg shadow-lg w-4/5 max-w-md">
<h2 className="text-lg font-bold mb-4">Listening...</h2>
<div className="flex items-center justify-center space-x-2 mb-4">
<div className={`w-2 h-10 bg-green-500 ${listening ? 'animate-pulse' : ''}`}></div>
<div className={`w-2 h-10 bg-green-500 ${listening ? 'animate-pulse' : ''}`}></div>
<div className={`w-2 h-10 bg-green-500 ${listening ? 'animate-pulse' : ''}`}></div>
<div className={`w-2 h-10 bg-green-500 ${listening ? 'animate-pulse' : ''}`}></div>
<div className={`w-2 h-10 bg-green-500 ${listening ? 'animate-pulse' : ''}`}></div>
</div>
<p className="text-gray-700 dark:text-gray-200">{transcript}</p>
<button
className="mt-4 bg-red-500 text-white px-4 py-2 rounded-full"
onClick={handleCloseModal}
>
Close
</button>
</div>
</div>
)}
</div>
);
};
This code renders the search box and modal:
- Search Box: Contains the input field and icons.
- Search Icon: Opens the modal and starts listening.
- Microphone Icon: Toggles speech recognition.
- Filter Icon: Placeholder for additional functionality.
- Modal: Displays when
isModalOpen
is true. - Listening Indicator: Shows animated bars when listening.
- Transcript: Displays the recognized speech.
- Close Button: Closes the modal and stops speech recognition.
Here is the complete code for reference:
'use client';
import React, { useState, useEffect, useRef } from 'react';
import SearchIcon from '@mui/icons-material/Search';
import Mic from '@mui/icons-material/Mic';
import { RiEqualizerLine } from 'react-icons/ri';
import SpeechRecognition, { useSpeechRecognition } from 'react-speech-recognition';
const Icon = ({ children, onClick, ariaLabel, className }) => (
<div onClick={onClick} aria-label={ariaLabel} className={`cursor-pointer ${className}`}>
{children}
</div>
);
export const SearchBox = () => {
const [isModalOpen, setIsModalOpen] = useState(false);
const [inputValue, setInputValue] = useState('');
const { transcript, listening, resetTranscript } = useSpeechRecognition();
const timeoutRef = useRef(null);
const startListening = () => {
resetTranscript();
SpeechRecognition.startListening({ continuous: true });
setIsModalOpen(true);
resetTimeout();
};
const stopListening = () => {
SpeechRecognition.stopListening();
setIsModalOpen(false);
clearTimeout(timeoutRef.current);
};
const handleMicClick = () => {
if (listening) {
stopListening();
} else {
startListening();
}
};
const handleCloseModal = () => {
stopListening();
};
const handleInputChange = (event) => {
setInputValue(event.target.value);
};
const resetTimeout = () => {
clearTimeout(timeoutRef.current);
timeoutRef.current = setTimeout(() => {
if (listening) {
stopListening();
}
}, 3000);
};
useEffect(() => {
if (listening) {
resetTimeout();
}
}, [transcript]);
useEffect(() => {
if (!isModalOpen && transcript) {
setInputValue(transcript.trim());
resetTranscript();
}
}, [isModalOpen, transcript, resetTranscript]);
if (!SpeechRecognition.browserSupportsSpeechRecognition()) {
return <span>Browser doesn't support speech recognition.</span>;
}
return (
<div>
<div className="flex text-center w-full max-w-80 items-center border dark:border-none dark:bg-slate-700 shadow-slate-400 bg-slate-100 rounded-full px-4 py-1">
<Icon onClick={handleMicClick} ariaLabel={'Search icon'} className="text-gray-400 mr-2">
<SearchIcon />
</Icon>
<input
type="text"
placeholder="Search"
value={inputValue}
onChange={handleInputChange}
className="outline-none bg-transparent text-gray-700 dark:text-gray-200 w-full"
/>
<Icon onClick={handleMicClick} ariaLabel={'Microphone icon'} className="text-gray-400 mr-1">
<Mic />
</Icon>
<Icon onClick={handleMicClick} ariaLabel={'Filter icon'} className="text-gray-400 mr-1">
<RiEqualizerLine />
</Icon>
</div>
{isModalOpen && (
<div className="fixed inset-0 flex items-center justify-center z-50">
<div className="bg-white dark:bg-slate-700 p-6 rounded-lg shadow-lg w-4/5 max-w-md">
<h2 className="text-lg font-bold mb-4">Listening...</h2>
<div className="flex items-center justify-center space-x-2 mb-4">
<div className={`w-2 h-10 bg-green-500 ${listening ? 'animate-pulse' : ''}`}></div>
<div className={`w-2 h-10 bg-green-500 ${listening ? 'animate-pulse' : ''}`}></div>
<div className={`w-2 h-10 bg-green-500 ${listening ? 'animate-pulse' : ''}`}></div>
<div className={`w-2 h-10 bg-green-500 ${listening ? 'animate-pulse' : ''}`}></div>
<div className={`w-2 h-10 bg-green-500 ${listening ? 'animate-pulse' : ''}`}></div>
</div>
<p className="text-gray-700 dark:text-gray-200">{transcript}</p>
<button
className="mt-4 bg-red-500 text-white px-4 py-2 rounded-full"
onClick={handleCloseModal}
>
Close
</button>
</div>
</div>
)}
</div>
);
};
We have now built a real-time speech recognition search box using Next.js, Tailwind CSS, and the react-speech-recognition
library. This component enhances user interaction by providing an accessible and interactive search feature.
Related Tags
Recommended
2m · 6min read
Web Development
2m · 6min read
Build a Real-time Speech Recognition Search Box with Next.js and Tailwind CSS
Building a real-time speech recognition search box using Next.js, Tailwind CSS, and the react-speech-recognition library
2m · 5min read
Web Development
2m · 5min read
How to Show Customized Relative Time with JavaScript
Learn how to create a JavaScript function to display relative time (like "5min ago" or "2y ago") by calculating the difference between the current date and an input date, converting it into various time units (seconds, minutes, hours, days, weeks, months, years), and returning the most appropriate unit as a string.
2m · 4min read
Web Development
2m · 4min read
How to Use Middleware in Next.js 14 for Route Protection
Implement middleware in Next.js 14 to protect routes, manage user authentication, handle role-based access. Middleware allows you to protect sensitive areas, such as user dashboards, while keeping public pages accessible to everyone.
2m · 5min read
Web Development
2m · 5min read
State Context vs Redux in React.js: When to Use Each One?
Learn the key differences between React's Context API and Redux for effective state management in your React.js applications, and discover which solution suits your project best.
2m · 4min read
Web Development
2m · 4min read
Build a Reusable Navbar Component for Multiple Pages Using HTML, CSS, and JavaScript
In this tutorial, we learned how to create a reusable navbar component using HTML, CSS, and JavaScript by dynamically loading the navbar into multiple pages, ensuring consistency and simplifying maintenance across the website.
3m · 4min read
Web Development
3m · 4min read
How to Integrate Dark Mode and Light Mode Toggle in Next.js with Tailwind CSS
Implement dynamic dark mode and light mode in Next.js with Tailwind CSS to improve user experience, accessibility, and visual customization.
4m · 6min read
Web Development
4m · 6min read
Cross-Origin Resource Sharing (CORS): How To Fix CORS
Cross-Origin Resource Sharing (CORS) is a browser mechanism that enables controlled access to resources from different domains, extending the same-origin policy while providing potential for cross-domain attacks if improperly configured.
4m · 5min read
Web Development
4m · 5min read
TypeScript Types vs Interfaces
Types vs Interfaces: Types in TypeScript are more flexible and can define a wider range of data types, including primitives, unions, intersections, tuples, and more, while interfaces are primarily used to describe the shape of objects and support declaration merging and extending, making them ideal for object-oriented programming and complex data structures
5m · 3min read
Web Development
5m · 3min read
The this Keyword in JavaScript
The this keyword in JavaScript is a reference to the object that a function is a property of. It's a fundamental concept in JavaScript, especially in object-oriented programming. Unlike in languages like Java, C#, or PHP, where this typically refers to the current instance of the class, JavaScript's this behaves differently and can be quite versatile.
6m · 8min read
Web Development
6m · 8min read
30 Common CSS Mistakes
30 CSS common mistakes we make includes: complicating selectors,Overuse of the “!important” declaration, Mishandling the z-index property, Duplicating code, Relying solely on color names and more