React
First-class React support with proper hooks and lifecycle management
The React component provides first-class React support with proper hooks and lifecycle management.
The React component uses the vanilla JS API under the hood, ensuring consistent behavior and proper cleanup.
Installation
npm install @cobbl-ai/feedback-widgetBasic Usage
import { FeedbackWidget } from '@cobbl-ai/feedback-widget/react'
const App = () => (
<div>
<h1>AI Response</h1>
<p>Your AI-generated content...</p>
<FeedbackWidget runId="prompt-run-id" />
</div>
)Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
runId | string | Yes | — | Run ID from prompt execution |
variant | 'trigger' | 'thumbs' | 'inline' | No | 'trigger' | Display variant |
position | WidgetPosition | No | 'bottom-right' | Flyout position |
triggerButtonText | string | No | 'Give Feedback' | Trigger button text |
colorScheme | 'auto' | 'light' | 'dark' | No | 'auto' | Color scheme mode |
onSuccess | (feedbackId: string) => void | No | — | Success callback |
onError | (error: Error) => void | No | — | Error callback |
className | string | No | — | Container CSS class |
style | React.CSSProperties | No | — | Container inline styles |
Display Variants
Trigger Variant (Default)
A text button that opens the feedback flyout:
<FeedbackWidget
runId="prompt-run-id"
variant="trigger"
triggerButtonText="Rate this response"
/>Thumbs Variant
Thumbs up/down buttons that immediately register feedback:
<FeedbackWidget runId="prompt-run-id" variant="thumbs" />Inline Variant
Full feedback form rendered directly:
<FeedbackWidget runId="prompt-run-id" variant="inline" />Chat Example
'use client'
import { FeedbackWidget } from '@cobbl-ai/feedback-widget/react'
interface Message {
id: string
content: string
runId: string
}
interface ChatComponentProps {
messages: Message[]
}
const ChatComponent = ({ messages }: ChatComponentProps) => {
return (
<div className="chat-container">
{messages.map((message) => (
<div key={message.id} className="message">
<p>{message.content}</p>
<FeedbackWidget runId={message.runId} variant="thumbs" />
</div>
))}
</div>
)
}In this example, messages are fetched from your server (where they're stored in the database with their runId from prompt execution). The server handles running prompts via the Admin SDK and storing responses, while the client component simply displays them with the feedback widget.
Dynamic Run ID
The widget automatically updates when props change:
const DynamicExample = () => {
const [runId, setRunId] = useState('initial-run-id')
const generateNewResponse = async () => {
const result = await client.runPrompt('my-prompt', { topic: 'New Topic' })
setRunId(result.runId)
}
return (
<div>
<button onClick={generateNewResponse}>Generate New</button>
<FeedbackWidget runId={runId} />
</div>
)
}Event Handling
Handle success and error events:
<FeedbackWidget
runId="prompt-run-id"
onSuccess={(feedbackId) => {
// Show success toast
toast.success('Thanks for your feedback!')
// Track analytics
analytics.track('feedback_submitted', { feedbackId })
}}
onError={(error) => {
// Show error toast
toast.error('Failed to submit feedback')
// Log error
console.error('Feedback error:', error)
}}
/>Styling
Using className
<FeedbackWidget runId="prompt-run-id" className="my-feedback-widget" />.my-feedback-widget {
--cobbl-primary: #6366f1;
--cobbl-primary-hover: #4f46e5;
}Using style prop
<FeedbackWidget
runId="prompt-run-id"
style={
{
'--cobbl-primary': '#6366f1',
'--cobbl-trigger-font-size': '14px',
} as React.CSSProperties
}
/>Tailwind CSS
<FeedbackWidget
runId="prompt-run-id"
className="[--cobbl-primary:#6366f1] [--cobbl-flyout-width:400px]"
/>See Styling for the complete list of CSS variables.
Flyout Positioning
Control the flyout position:
<FeedbackWidget runId="prompt-run-id" variant="trigger" position="top" />Available positions:
top-left,top,top-rightleft,rightbottom-left,bottom,bottom-right(default)
The flyout automatically adjusts if it would overflow the viewport.
Color Scheme
Control the widget's color scheme:
// Auto (default) - follows system preference
<FeedbackWidget runId="prompt-run-id" colorScheme="auto" />
// Force light theme
<FeedbackWidget runId="prompt-run-id" colorScheme="light" />
// Force dark theme
<FeedbackWidget runId="prompt-run-id" colorScheme="dark" />Syncing with Your Theme
Bind the colorScheme prop to your app's theme state:
import { useTheme } from 'next-themes' // or your theme provider
const MyComponent = () => {
const { theme } = useTheme()
return (
<FeedbackWidget
runId="prompt-run-id"
colorScheme={theme === 'dark' ? 'dark' : 'light'}
/>
)
}With auto mode, the widget automatically updates when the user changes their
system color scheme preference.
See Styling for customizing colors per scheme.
Multiple Widgets
Render multiple widgets for different responses:
const ResponseList = ({ responses }) => (
<div>
{responses.map((response) => (
<div key={response.id} className="response-card">
<p>{response.content}</p>
<FeedbackWidget runId={response.runId} variant="thumbs" />
</div>
))}
</div>
)Server Components (Next.js)
The FeedbackWidget must be used in a client component:
import { ChatMessages } from './ChatMessages'
// Server component
const ChatPage = async () => {
const messages = await getMessages()
return <ChatMessages initialMessages={messages} />
}'use client'
import { FeedbackWidget } from '@cobbl-ai/feedback-widget/react'
// Client component
export const ChatMessages = ({ initialMessages }) => {
return (
<div>
{initialMessages.map((msg) => (
<div key={msg.id}>
<p>{msg.content}</p>
<FeedbackWidget runId={msg.runId} variant="thumbs" />
</div>
))}
</div>
)
}TypeScript
Full TypeScript support is included:
import { FeedbackWidget } from '@cobbl-ai/feedback-widget/react'
import type { FeedbackWidgetProps } from '@cobbl-ai/feedback-widget/react'
const MyWidget = (props: Partial<FeedbackWidgetProps>) => (
<FeedbackWidget runId="required-run-id" {...props} />
)import type {
WidgetPosition,
WidgetVariant,
ColorScheme,
} from '@cobbl-ai/feedback-widget'
const position: WidgetPosition = 'top-right'
const variant: WidgetVariant = 'thumbs'
const colorScheme: ColorScheme = 'auto'See TypeScript for type definitions.