npm package: @futurebase/feedback
Description: Embeddable feedback widget for FutureBase — React components for collecting user feedback
Latest version: 0.1.1

# @futurebase/feedback

Embeddable feedback widget for [FutureBase](https://futurebase.io). Drop-in React components for collecting star ratings and text feedback from your users.

## Installation

```bash
npm install @futurebase/feedback
```

### Peer Dependencies

React 18+ is required:

```bash
npm install react react-dom
```

## Quick Start

Wrap your app with `FeedbackProvider` and add a feedback component:

```tsx
import { FeedbackProvider, FeedbackBubble } from "@futurebase/feedback/react";

function App() {
  return (
    <FeedbackProvider slug="your-board-slug">
      <FeedbackBubble />
    </FeedbackProvider>
  );
}
```

## Components

### `FeedbackProvider`

Required wrapper that provides the feedback context to all child components. Handles API client setup and board configuration fetching.

```tsx
<FeedbackProvider slug="your-board-slug" theme={{ primaryColor: "#2563eb" }}>
  {children}
</FeedbackProvider>
```

| Prop | Type | Required | Description |
|------|------|----------|-------------|
| `slug` | `string` | Yes | Your feedback board slug |
| `theme` | `FeedbackTheme` | No | Global theme overrides |
| `children` | `ReactNode` | Yes | Child components |

### `FeedbackBubble`

A floating button that opens a feedback popup when clicked. Supports star ratings and text input.

```tsx
<FeedbackBubble
  position="bottom-right"
  fields={["stars", "text"]}
  labels={{ title: "Send us feedback" }}
/>
```

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `position` | `FeedbackPosition` | `"bottom-right"` | Screen position of the bubble |
| `fields` | `FeedbackField[]` | `["stars", "text"]` | Which input fields to show |
| `theme` | `FeedbackTheme` | — | Theme overrides (merges with provider theme) |
| `labels` | `FeedbackLabels` | — | Custom text labels |
| `context` | `Record<string, unknown>` | — | Extra context sent with the submission |
| `icon` | `ReactNode` | — | Custom icon for the bubble button |
| `onSubmitSuccess` | `(data: FeedbackData) => void` | — | Called after successful submission |
| `onSubmitError` | `(error: Error) => void` | — | Called on submission error |

### `InlineFeedback`

An embedded feedback form you can place anywhere in your layout.

```tsx
<InlineFeedback
  fields={["stars", "text"]}
  labels={{ title: "How are we doing?" }}
  compact
/>
```

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `fields` | `FeedbackField[]` | `["stars", "text"]` | Which input fields to show |
| `theme` | `FeedbackTheme` | — | Theme overrides |
| `labels` | `FeedbackLabels` | — | Custom text labels |
| `context` | `Record<string, unknown>` | — | Extra context sent with the submission |
| `compact` | `boolean` | `false` | Use compact styling |
| `onSubmitSuccess` | `(data: FeedbackData) => void` | — | Called after successful submission |
| `onSubmitError` | `(error: Error) => void` | — | Called on submission error |

### `FeedbackWrapper`

Wraps any element and shows a small feedback trigger on hover. Useful for collecting contextual feedback on specific UI elements.

```tsx
<FeedbackWrapper id="pricing-section">
  <PricingTable />
</FeedbackWrapper>
```

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `id` | `string` | — | **Required.** Identifier for the wrapped element |
| `children` | `ReactNode` | — | **Required.** Element to wrap |
| `position` | `FeedbackPosition` | `"top-right"` | Position of the trigger button |
| `fields` | `FeedbackField[]` | `["stars", "text"]` | Which input fields to show |
| `theme` | `FeedbackTheme` | — | Theme overrides |
| `labels` | `FeedbackLabels` | — | Custom text labels |
| `context` | `Record<string, unknown>` | — | Extra context sent with the submission |
| `className` | `string` | — | CSS class for the wrapper div |
| `onSubmitSuccess` | `(data: FeedbackData) => void` | — | Called after successful submission |
| `onSubmitError` | `(error: Error) => void` | — | Called on submission error |

### Compound Components

For full control over the feedback form layout, use the compound component API:

```tsx
import {
  Feedback,
  FeedbackLabel,
  FeedbackStars,
  FeedbackText,
  FeedbackSubmit,
} from "@futurebase/feedback/react";

<Feedback id="custom-form">
  <FeedbackLabel>Rate your experience</FeedbackLabel>
  <FeedbackStars />
  <FeedbackText placeholder="Any thoughts?" />
  <FeedbackSubmit label="Send" />
</Feedback>
```

#### `Feedback`

Root compound component that manages form state.

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `id` | `string` | — | **Required.** Identifier for this feedback form |
| `children` | `ReactNode` | — | **Required.** Compound child components |
| `context` | `Record<string, unknown>` | — | Extra context sent with the submission |
| `theme` | `FeedbackTheme` | — | Theme overrides |
| `successMessage` | `string` | `"Thank you for your feedback!"` | Message shown after submission |
| `onSubmitSuccess` | `(data: FeedbackData) => void` | — | Called after successful submission |
| `onSubmitError` | `(error: Error) => void` | — | Called on submission error |

#### `FeedbackLabel`

Renders a heading for the form. Accepts `children: ReactNode`.

#### `FeedbackStars`

Star rating input (1-5). Auto-submits if no `FeedbackSubmit` is present.

#### `FeedbackText`

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `placeholder` | `string` | `"Tell us what you think..."` | Textarea placeholder |
| `rows` | `number` | `3` | Number of visible text rows |

Supports `Ctrl/Cmd + Enter` to submit.

#### `FeedbackSubmit`

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `label` | `string` | `"Send feedback"` | Button label |
| `submittingLabel` | `string` | `"Sending..."` | Label shown while submitting |

### `StarRating`

Standalone star rating component if you need just the stars.

```tsx
import { StarRating } from "@futurebase/feedback/react";

<StarRating value={rating} onChange={setRating} max={5} />
```

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `value` | `number` | — | **Required.** Current rating value |
| `onChange` | `(value: number) => void` | — | **Required.** Called when a star is clicked |
| `max` | `number` | `5` | Maximum number of stars |

## Hooks

### `useFeedback()`

Access the feedback context from any component inside `FeedbackProvider`.

```tsx
import { useFeedback } from "@futurebase/feedback/react";

function MyComponent() {
  const { boardInfo, loading, submitFeedback, theme } = useFeedback();

  const handleSubmit = async () => {
    await submitFeedback({ rating: 5, text: "Great!" });
  };
}
```

**Returns `FeedbackContextValue`:**

| Property | Type | Description |
|----------|------|-------------|
| `slug` | `string` | Board slug |
| `boardInfo` | `BoardInfoOutput \| null` | Board configuration from the server |
| `loading` | `boolean` | Whether board info is still loading |
| `submitFeedback` | `(data, context?) => Promise<{ feedbackId }>` | Submit feedback programmatically |
| `theme` | `FeedbackTheme` | Resolved theme (provider + board settings) |

## Types

All types are exported from the root entry point:

```tsx
import type {
  FeedbackData,
  FeedbackField,
  FeedbackPosition,
  FeedbackTheme,
  FeedbackLabels,
  BaseFeedbackProps,
  FeedbackBubbleProps,
  InlineFeedbackProps,
  FeedbackWrapperProps,
} from "@futurebase/feedback";
```

### `FeedbackTheme`

```ts
type FeedbackTheme = {
  primaryColor?: string;
  backgroundColor?: string;
  textColor?: string;
  borderColor?: string;
  borderRadius?: string;
  fontFamily?: string;
};
```

### `FeedbackLabels`

```ts
type FeedbackLabels = {
  title?: string;
  placeholder?: string;
  submit?: string;
  success?: string;
};
```

### `FeedbackField`

```ts
type FeedbackField = "stars" | "text";
```

### `FeedbackPosition`

```ts
type FeedbackPosition = "bottom-right" | "bottom-left" | "top-right" | "top-left";
```

### `FeedbackData`

```ts
type FeedbackData = {
  rating?: number;
  text?: string;
};
```

## Theming

The widget supports both light and dark modes automatically. Dark mode activates when the parent element has a `.dark` class or `[data-theme="dark"]` attribute (compatible with Tailwind CSS and next-themes).

Override the default theme via the `theme` prop on `FeedbackProvider` or on individual components:

```tsx
<FeedbackProvider
  slug="my-board"
  theme={{
    primaryColor: "#8b5cf6",
    backgroundColor: "#1a1a2e",
    textColor: "#e0e0e0",
    borderRadius: "8px",
    fontFamily: "'Inter', sans-serif",
  }}
>
  <FeedbackBubble />
</FeedbackProvider>
```

## License

MIT