Cobbl

JavaScript

Stripe Elements-style API for programmatic control of the feedback widget

The JavaScript API provides a Stripe Elements-style interface for full programmatic control. Perfect for SPAs, JavaScript apps, or any framework.

Installation

npm install @cobbl-ai/feedback-widget

Basic Usage

import { cobblWidget } from '@cobbl-ai/feedback-widget'

// Create a widget instance
const widget = cobblWidget.create({
  runId: 'prompt-run-id',
})

// Mount to a container
widget.mount('#feedback-container')

API Reference

cobblWidget.create()

Create a new widget instance with configuration:

const widget = cobblWidget.create({
  runId: 'prompt-run-id',
  variant: 'trigger',
  position: 'bottom-right',
  triggerButtonText: 'Rate this response',
  onSuccess: (feedbackId) => {
    console.log('Feedback submitted:', feedbackId)
  },
  onError: (error) => {
    console.error('Feedback failed:', error)
  },
})

You can also create a widget from an element with data attributes:

const element = document.getElementById('my-widget')
const widget = cobblWidget.create(element)

Configuration Options

All available options for cobblWidget.create():

OptionTypeRequiredDefaultDescription
runIdstringYesRun ID from prompt execution
variant'trigger' | 'thumbs' | 'inline'No'trigger'Display variant
positionWidgetPositionNo'bottom-right'Flyout position
triggerButtonTextstringNo'Give Feedback'Trigger button text
colorScheme'auto' | 'light' | 'dark'No'auto'Color scheme mode
onSuccess(feedbackId: string) => voidNoSuccess callback
onError(error: Error) => voidNoError callback

widget.mount()

Mount the widget to a DOM element:

// Mount using a CSS selector
widget.mount('#feedback-container')

// Mount using a DOM element
const container = document.getElementById('feedback-container')
widget.mount(container)

widget.update()

Update the widget configuration dynamically:

// Update a single property
widget.update({ runId: 'new-run-id' })

// Update multiple properties
widget.update({
  runId: 'new-run-id',
  variant: 'thumbs',
  position: 'top',
})

widget.getConfig()

Get the current widget configuration:

const config = widget.getConfig()
console.log(config.runId)
console.log(config.variant)

widget.destroy()

Unmount and clean up the widget:

widget.destroy()

WidgetInstance Interface

interface WidgetInstance {
  mount(container: string | HTMLElement): void
  update(config: Partial<FeedbackWidgetConfig>): void
  destroy(): void
  getConfig(): FeedbackWidgetConfig
}

Display Variants

Trigger Variant (Default)

A text button that opens the feedback flyout:

const widget = cobblWidget.create({
  runId: 'prompt-run-id',
  variant: 'trigger',
  triggerButtonText: 'Give Feedback',
})
widget.mount('#container')

Thumbs Variant

Thumbs up/down buttons that immediately register feedback:

const widget = cobblWidget.create({
  runId: 'prompt-run-id',
  variant: 'thumbs',
})
widget.mount('#container')

Inline Variant

Full feedback form rendered directly:

const widget = cobblWidget.create({
  runId: 'prompt-run-id',
  variant: 'inline',
})
widget.mount('#container')

Flyout Positioning

Control where the flyout appears relative to the trigger:

const widget = cobblWidget.create({
  runId: 'prompt-run-id',
  variant: 'trigger',
  position: 'top-right',
})
widget.mount('#container')

Available positions:

  • top-left, top, top-right
  • left, right
  • bottom-left, bottom, bottom-right (default)

Color Scheme

Control the widget's color scheme:

// Auto (default) - follows system preference
const widget = cobblWidget.create({
  runId: 'prompt-run-id',
  colorScheme: 'auto',
})

// Force light theme
const lightWidget = cobblWidget.create({
  runId: 'prompt-run-id',
  colorScheme: 'light',
})

// Force dark theme
const darkWidget = cobblWidget.create({
  runId: 'prompt-run-id',
  colorScheme: 'dark',
})

Dynamic Color Scheme Updates

Update the color scheme at runtime:

const widget = cobblWidget.create({
  runId: 'prompt-run-id',
  colorScheme: 'auto',
})
widget.mount('#container')

// Later, switch to dark mode
widget.update({ colorScheme: 'dark' })

See Styling for customizing colors per scheme.

Complete Example

import { cobblWidget } from '@cobbl-ai/feedback-widget'
import { CobblAdminClient } from '@cobbl-ai/sdk'

const client = new CobblAdminClient({ apiKey: 'your-api-key' })

// Store widget reference for cleanup
let feedbackWidget: ReturnType<typeof cobblWidget.create> | null = null

const runPromptAndShowWidget = async () => {
  // Run the prompt
  const result = await client.runPrompt('my-prompt', {
    topic: 'AI Safety',
  })

  // Display the response
  document.getElementById('response')!.textContent = result.output

  // Clean up existing widget if any
  if (feedbackWidget) {
    feedbackWidget.destroy()
  }

  // Create and mount feedback widget
  feedbackWidget = cobblWidget.create({
    runId: result.runId,
    position: 'bottom-right',
    triggerButtonText: 'Rate this response',
    onSuccess: (feedbackId) => {
      console.log('Feedback submitted:', feedbackId)
    },
  })

  feedbackWidget.mount('#feedback-container')
}

// Clean up when navigating away
window.addEventListener('beforeunload', () => {
  feedbackWidget?.destroy()
})

Multiple Widgets

You can have multiple widget instances on the same page:

import { cobblWidget } from '@cobbl-ai/feedback-widget'

// Create widgets for different responses
const widget1 = cobblWidget.create({ runId: 'run-1', variant: 'thumbs' })
const widget2 = cobblWidget.create({ runId: 'run-2', variant: 'thumbs' })
const widget3 = cobblWidget.create({ runId: 'run-3', variant: 'inline' })

// Mount to different containers
widget1.mount('#response-1-feedback')
widget2.mount('#response-2-feedback')
widget3.mount('#response-3-feedback')

Dynamic Updates

Update the widget when the run changes:

const widget = cobblWidget.create({
  runId: 'initial-run-id',
})
widget.mount('#container')

// Later, update the run ID
const newResult = await client.runPrompt('my-prompt', { topic: 'New Topic' })
widget.update({ runId: newResult.runId })

Event Callbacks

Handle success and error events:

const widget = cobblWidget.create({
  runId: 'prompt-run-id',
  onSuccess: (feedbackId) => {
    // Called when feedback is successfully submitted
    console.log('Feedback ID:', feedbackId)

    // Show a toast notification
    showToast('Thanks for your feedback!')

    // Track analytics
    analytics.track('feedback_submitted', { feedbackId })
  },
  onError: (error) => {
    // Called when feedback submission fails
    console.error('Feedback error:', error.message)

    // Show error to user
    showToast('Failed to submit feedback. Please try again.')
  },
})

Styling

Apply custom styles using CSS variables:

#feedback-container {
  --cobbl-primary: #6366f1;
  --cobbl-primary-hover: #4f46e5;
  --cobbl-flyout-width: 350px;
}

See Styling for the complete list of CSS variables.

TypeScript Support

Full TypeScript support is included:

import { cobblWidget } from '@cobbl-ai/feedback-widget'
import type {
  FeedbackWidgetConfig,
  WidgetInstance,
  ColorScheme,
} from '@cobbl-ai/feedback-widget'

const config: FeedbackWidgetConfig = {
  runId: 'prompt-run-id',
  variant: 'trigger',
  colorScheme: 'auto',
}

const widget: WidgetInstance = cobblWidget.create(config)

See TypeScript for type definitions.

Next Steps

On this page