voice-feedback-widget
v1.0.4
Published
A beautiful, accessible voice feedback widget for React applications
Maintainers
Readme
Voice Feedback Widget
A beautiful, accessible voice feedback widget for React applications. This package provides a complete feedback form with voice recording capabilities, built with modern React patterns and accessibility in mind.
Features
- 🎤 Voice Recording: Record audio feedback with live waveform visualization
- 📝 Text Input: Optional text feedback alongside voice
- 🎨 Beautiful UI: Modern, minimal design with smooth animations
- ♿ Accessible: Full keyboard navigation and screen reader support
- 📱 Responsive: Works on desktop and mobile devices
- 🎯 TypeScript: Fully typed for better developer experience
- 🔧 Customizable: Extensive customization options
- ⚡ Performance: Optimized with TanStack React Query and efficient rendering
- 🎵 Live Waveform: Real-time audio visualization during recording
- 🎛️ Microphone Selection: Choose from available audio input devices
- ⏱️ Configurable Duration: Set custom maximum recording duration
- 📦 Minimizable: Collapsible widget interface
Installation
npm install voice-feedback-widget
# or
yarn add voice-feedback-widget
# or
pnpm add voice-feedback-widgetQuick Start
import { VoiceFeedbackWidget } from "voice-feedback-widget";
function App() {
return (
<div>
<h1>My App</h1>
<VoiceFeedbackWidget
className="dark"
options={{
apiEndpoint: "/api/feedback",
onSuccess: (response) => {
console.log("Feedback submitted:", response);
},
onError: (error) => {
console.error("Submission failed:", error);
},
}}
/>
</div>
);
}Props
VoiceFeedbackWidget
The component accepts two props:
| Prop | Type | Description |
| ----------- | -------------------------- | ---------------------------- |
| className | string | Custom CSS class name |
| options | VoiceFeedbackWidgetProps | Configuration options object |
VoiceFeedbackWidgetProps
| Prop | Type | Default | Description |
| ---------------------- | ------------------------------------------------ | -------------------------------------------------------- | ------------------------------------------------ |
| apiEndpoint | string | "https://voice-feedback-agent.vercel.app/api/feedback" | API endpoint URL for submitting feedback |
| onSuccess | (response: FeedbackSubmissionResponse) => void | - | Callback when feedback is successfully submitted |
| onError | (error: Error) => void | - | Callback when feedback submission fails |
| title | string | "Feedback Form" | Widget title |
| description | string | "Share your feedback with us" | Widget description |
| defaultMinimized | boolean | false | Whether to show the widget minimized by default |
| maxRecordingDuration | number | 90 | Maximum recording duration in seconds |
| form | FormFieldConfig | See below | Form field configuration |
FormFieldConfig
| Prop | Type | Default | Description |
| --------------- | ------------------- | ------------------- | ----------------------------------------------------------- |
| show | FormField[] | ["name", "email"] | Array of fields to display: "name", "email", "phone" |
| defaultValues | FormDefaultValues | - | Default values to prefill (works even if fields are hidden) |
| required | boolean | true | Whether visible fields are required |
FormField Type
Available field options: "name" | "email" | "phone"
Form Configuration Examples
Hide All User Fields (Feedback Only)
<VoiceFeedbackWidget
className="dark"
options={{
apiEndpoint: "/api/feedback",
form: {
show: [], // No fields shown, only feedback input
},
}}
/>Show Specific Fields
<VoiceFeedbackWidget
className="dark"
options={{
apiEndpoint: "/api/feedback",
form: {
show: ["name", "email"], // Only show name and email
required: true, // Make them required
},
}}
/>Prefill Values (Including Hidden Fields)
<VoiceFeedbackWidget
className="dark"
options={{
apiEndpoint: "/api/feedback",
form: {
show: ["name"], // Only show name
defaultValues: {
name: "John Doe",
email: "[email protected]", // Hidden but will be sent with form
phone: "+1234567890", // Hidden but will be sent with form
},
},
}}
/>Make Fields Optional
<VoiceFeedbackWidget
className="dark"
options={{
apiEndpoint: "/api/feedback",
form: {
show: ["name", "email", "phone"],
required: false, // All fields are optional
},
}}
/>Complete Example with All Options
<VoiceFeedbackWidget
className="dark"
options={{
apiEndpoint: "/api/feedback",
title: "Voice Feedback",
description: "Share your thoughts with us",
maxRecordingDuration: 60,
defaultMinimized: false,
onSuccess: (response) => {
console.log("Feedback submitted successfully:", response);
},
onError: (error) => {
console.error("Failed to submit feedback:", error);
},
form: {
show: ["name", "phone"],
defaultValues: {
name: "John Doe",
email: "[email protected]",
},
required: true,
},
}}
/>API Integration
The widget sends data to your API endpoint using FormData with the following fields:
name(string, optional): User's nameemail(string, optional): User's emailphone(string, optional): User's phone numbermessage(string, optional): Text feedbackaudio(Blob, optional): Audio recording as WebM file
Important Notes:
- All user fields (
name,email,phone) are optional - Either
messageoraudiomust be provided (or both) - The widget includes a 30-second timeout for API requests
- Audio files are sent as WebM format with filename
feedback.webm
Expected API Response
Your API should return a JSON response with this structure:
interface FeedbackSubmissionResponse {
success: boolean;
message: string;
feedbackId?: string; // Optional unique identifier
}Example API Handler (Next.js)
// app/api/feedback/route.ts
import { NextRequest, NextResponse } from "next/server";
export async function POST(request: NextRequest) {
try {
const formData = await request.formData();
const name = formData.get("name") as string | null;
const email = formData.get("email") as string | null;
const phone = formData.get("phone") as string | null;
const message = formData.get("message") as string | null;
const audio = formData.get("audio") as File | null;
// Validate that either message or audio is provided
if (!message?.trim() && !audio) {
return NextResponse.json(
{ success: false, error: "Either text or audio feedback is required" },
{ status: 400 }
);
}
// Process the feedback data
// Save to database, send notifications, etc.
console.log({
name,
email,
phone,
message: message || "[Audio feedback]",
audioReceived: !!audio,
audioSize: audio?.size,
});
return NextResponse.json({
success: true,
message: "Feedback submitted successfully",
feedbackId: `feedback_${Date.now()}`,
});
} catch (error) {
console.error("Feedback submission error:", error);
return NextResponse.json(
{ success: false, error: "Failed to submit feedback" },
{ status: 500 }
);
}
}Advanced Usage
Custom Styling
The widget uses Tailwind CSS with CSS custom properties for theming. You can customize the appearance by:
- Using the
classNameprop to apply custom styles:
<VoiceFeedbackWidget
className="custom-widget-theme"
options={{ apiEndpoint: "/api/feedback" }}
/>- Overriding CSS custom properties in your global styles:
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 222.2 84% 4.9%;
--muted: 210 40% 98%;
--muted-foreground: 215.4 16.3% 46.9%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
}Widget Positioning
The widget is positioned as a fixed element in the bottom-right corner by default. You can customize its position:
.voice-feedback-widget {
position: fixed;
bottom: 1rem;
right: 1rem;
z-index: 50;
}
/* Custom positioning */
.custom-position .voice-feedback-widget {
bottom: 2rem;
left: 2rem;
right: auto;
}Audio Recording Features
The widget includes advanced audio recording capabilities:
- Live waveform visualization during recording
- Microphone device selection from available audio inputs
- Configurable recording duration (default: 90 seconds)
- Audio playback to review recordings before submission
- Automatic timeout to prevent overly long recordings
- WebM format for optimal browser compatibility
Form Validation
The widget includes comprehensive form validation:
- Dynamic schema generation based on visible fields
- Real-time validation with error messages
- Required field validation (configurable)
- Email format validation
- Character limits for all text fields
- Audio or text requirement (at least one must be provided)
Requirements
- React 18+
- Modern browser with Web Audio API support
- Microphone permissions
- HTTPS connection (required for microphone access in production)
Dependencies
The widget uses the following key dependencies:
- TanStack React Query - For API state management
- React Hook Form - For form handling and validation
- Zod - For schema validation
- Motion - For smooth animations
- Lucide React - For icons
- Tailwind CSS - For styling
Browser Support
- Chrome 66+ (recommended)
- Firefox 60+
- Safari 11+
- Edge 79+
Note: Audio recording requires HTTPS in production environments.
TypeScript Support
The package is fully typed with TypeScript definitions included. All props, callbacks, and return types are properly typed for excellent developer experience.
License
MIT
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Changelog
v1.0.0
- Initial release
- Voice recording with live waveform
- Configurable form fields
- Minimizable widget interface
- Full TypeScript support
- Comprehensive accessibility features
