The SpeechPanelComponent provides a user interface for speech recognition and text-to-speech capabilities. It acts as a control panel with buttons for starting/stopping voice recognition, speaking text, and clearing form content.
Overview
This standalone component offers:
Voice recognition controls (start/stop listening)
Text-to-speech functionality
Form clearing capability
Visual feedback during listening state
Error state handling
@ Component ({
selector: 'app-speech-panel' ,
templateUrl: './speech-panel.component.html' ,
styleUrl: './speech-panel.component.css' ,
standalone: true
})
Location: src/app/_components/speech-panel/speech-panel.component.ts:4-9
This is a standalone component and can be imported directly without a module declaration.
Properties
Icon assets
ListeningButtonIconOn : string = './assets/images/mic_on.gif' ;
ListeningButtonIconOff : string = './assets/images/mic_off.gif' ;
SpeakerIcon : string = './assets/images/speaker_on.gif' ;
clearFormIcon : string = './assets/images/clearForm.gif' ;
Location: speech-panel.component.ts:12-15
These properties define the paths to icon assets used in the control panel buttons.
Event emitters
clickEventSpeak
clickEventClearText
@ Output () clickEventSpeak = new EventEmitter < string >();
Emits when the speak button is clicked, passing the text to be spoken. Location: speech-panel.component.ts:16 @ Output () clickEventClearText = new EventEmitter < void >();
Emits when the clear button is clicked, signaling the parent component to clear form data. Location: speech-panel.component.ts:17
Constructor
Injects the SpeechService for speech functionality:
constructor ( public speechService : SpeechService ) {}
Location: speech-panel.component.ts:19-22
Methods
speakText()
Triggers text-to-speech functionality and emits the spoken text to the parent component.
Location: speech-panel.component.ts:24-30
speakText (): void {
this . clickEventSpeak . emit ( this . speechService . speakText ());
}
Process:
Invoke speech service
Calls speechService.speakText() to speak the current text
Emit event
Emits the text through clickEventSpeak for parent component handling
clearText()
Emits an event to clear form text in the parent component.
Location: speech-panel.component.ts:32-37
clearText (): void {
this . clickEventClearText . emit ();
}
Template structure
The component renders a control panel with four buttons and status feedback:
< div >
< button (click) = "this.speechService.startListening()" [disabled] = "this.speechService.isListening" >
< img class = "imgSearch" [src] = "this.ListeningButtonIconOn" >
</ button >
< button (click) = "this.speechService.stopListening()" [disabled] = "!this.speechService.isListening" >
< img class = "imgSearch" [src] = "this.ListeningButtonIconOff" >
</ button >
< button (click) = "this.speakText()" [disabled] = "this.speechService.isListening" >
< img class = "imgSearch" [src] = "this.SpeakerIcon" >
</ button >
< button (click) = "this.clearText()" >
< img class = "imgSearch" [src] = "this.clearFormIcon" alt = "new search" >
</ button >
</ div >
Location: speech-panel.component.html:1-6
Start listening Disabled when speechService.isListening is true
Stop listening Disabled when speechService.isListening is false
Speak text Disabled when speechService.isListening is true
Status feedback
The template displays real-time status information:
< div >
@if ((this.speechService.isListening) && (!this.speechService.error)) {
< span class = "col col-form-label" > [Listening...] </ span >
}
@if (this.speechService.error) {
< span class = "col col-form-label" class = "error" >
< p > Error: {{ this.speechService.error }} </ p >
</ span >
}
</ div >
Location: speech-panel.component.html:7-16
The template uses Angular’s new control flow syntax (@if) for conditional rendering.
Usage
Importing the component
Since this is a standalone component, import it directly:
import { SpeechPanelComponent } from './path/to/speech-panel/speech-panel.component' ;
@ Component ({
selector: 'app-my-component' ,
standalone: true ,
imports: [ SpeechPanelComponent ],
// ...
})
export class MyComponent {
// ...
}
Using in templates
< app-speech-panel
(clickEventSpeak) = "onSpeakText($event)"
(clickEventClearText) = "onClearText()" >
</ app-speech-panel >
Handling events in parent component
export class ParentComponent {
onSpeakText ( text : string ) : void {
console . log ( 'Speaking:' , text );
// Handle spoken text
}
onClearText () : void {
// Clear form fields or reset state
this . formData = '' ;
}
}
Integration example
Complete example showing integration with a form:
Parent component
With signals
import { Component } from '@angular/core' ;
import { SpeechPanelComponent } from './speech-panel/speech-panel.component' ;
import { FormsModule } from '@angular/forms' ;
@ Component ({
selector: 'app-search-form' ,
standalone: true ,
imports: [ SpeechPanelComponent , FormsModule ],
template: `
<div class="search-container">
<input [(ngModel)]="searchText" type="text" placeholder="Enter search query">
<app-speech-panel
(clickEventSpeak)="handleSpeak($event)"
(clickEventClearText)="handleClear()">
</app-speech-panel>
<button (click)="search()">Search</button>
</div>
`
})
export class SearchFormComponent {
searchText : string = '' ;
handleSpeak ( text : string ) : void {
console . log ( 'Spoken text:' , text );
// Optionally update searchText with spoken content
}
handleClear () : void {
this . searchText = '' ;
}
search () : void {
console . log ( 'Searching for:' , this . searchText );
// Perform search
}
}
import { Component , signal } from '@angular/core' ;
import { SpeechPanelComponent } from './speech-panel/speech-panel.component' ;
@ Component ({
selector: 'app-search-form' ,
standalone: true ,
imports: [ SpeechPanelComponent ],
template: `
<div>
<p>Search query: {{ searchText() }}</p>
<app-speech-panel
(clickEventSpeak)="handleSpeak($event)"
(clickEventClearText)="handleClear()">
</app-speech-panel>
</div>
`
})
export class SearchFormComponent {
searchText = signal < string >( '' );
handleSpeak ( text : string ) : void {
this . searchText . set ( text );
}
handleClear () : void {
this . searchText . set ( '' );
}
}
SpeechService integration
The component relies on the SpeechService for core functionality:
Service properties
interface SpeechService {
isListening : boolean ; // Current listening state
error : string | null ; // Error message if any
startListening () : void ; // Start voice recognition
stopListening () : void ; // Stop voice recognition
speakText () : string ; // Speak and return current text
}
State management
The component’s UI automatically reflects the service state:
State-based button disabling
// Start button disabled when listening
[ disabled ] = "this.speechService.isListening"
// Stop button disabled when not listening
[ disabled ] = "!this.speechService.isListening"
// Speak button disabled during listening
[ disabled ] = "this.speechService.isListening"
Styling considerations
The component uses these CSS classes:
.imgSearch - Applied to button images
.col.col-form-label - Status text styling
.error - Error message styling
Customize these in your global styles or component styles:
.imgSearch {
width : 32 px ;
height : 32 px ;
cursor : pointer ;
}
.col-form-label {
font-size : 14 px ;
color : #333 ;
}
.error {
color : #dc3545 ;
font-weight : bold ;
}
Accessibility
All buttons are keyboard-accessible through standard tab navigation and can be activated with Enter or Space keys.
Add aria-label attributes to buttons for better screen reader support: < button
(click) = "speechService.startListening()"
[disabled] = "speechService.isListening"
aria-label = "Start voice recognition" >
< img [src] = "ListeningButtonIconOn" alt = "Start listening" >
</ button >
The component provides visual feedback through:
Disabled button states
Status text display
Animated GIF icons (when listening)
Use cases
The SpeechPanelComponent is ideal for:
Search forms Voice-enabled search interfaces
Data entry Hands-free form filling
Accessibility Alternative input methods for users with disabilities
Mobile apps Touch-friendly voice controls