React component reference
Package: @bootstrapware/feedback
Styles: @bootstrapware/feedback/styles.css
Import styles once near the feature. Use a Client Component in Next.js App Router. Bootstrapware does not authenticate board end users, pass user from your session.
Props
| Prop | Type | Required | Notes |
|---|---|---|---|
| user | FeedbackAuthor | null | recommended | Opaque stable id. Optional name, email, avatarUrl for display. |
| adapter | FeedbackAdapter | BYO / local | If set, wins over Hosted. Use createLocalAdapter or your own API. |
| boardId | string | Hosted / BYO config | With publishableKey for Hosted. Defaults to brd_local for local adapter. |
| publishableKey | string | Hosted | Browser-safe. Never put secret keys in the client. |
| apiBaseUrl | string | no | Defaults to https://feedback.bootstrapware.co |
| posts | FeedbackPost[] | no | Seed posts for createLocalAdapter / demos. |
| config | Partial<FeedbackBoardConfig> | no | Overrides toggles / empty state until Hosted config loads. |
| theme | "light" | "dark" | no | Omit for the light cream default. No data-theme and no system theme. |
| presentation | "section" | "modal" | "window" | "launcher" | no | Default section (inline). Modal, window, and launcher start closed unless defaultOpen. Escape closes them. The backdrop closes modal and launcher. |
| defaultOpen | boolean | no | Open modal, window, or launcher on first render. Ignored for section. |
| focusPostId | string | no | Pin and focus this post on load. Also honors #bsw-fb-post-<id> on the host page. Fetches via listPosts({ postId }) when the post is not on the first page. |
| authorToken | string | no | Short-lived host-signed assertion from POST /api/v1/author-tokens (secret key). Required when the board sets requireAuthorToken. |
| className | string | no | Wrapper class for layout. |
Theme
theme is "light" | "dark". Omit it and the board stays the light cream default: the root has no data-theme attribute. theme="light" sets data-theme="light" and keeps those light tokens. theme="dark" sets data-theme="dark" and applies the dark shell. v1 does not follow prefers-color-scheme or the system theme.
Hosts may set these CSS custom properties on the embed root (.bsw-fb). These overrides are the supported API. Do not fight .bsw-* classes. When theme="dark" is set, target .bsw-fb[data-theme="dark"] so your values win over the dark defaults.
- --bsw-fb-bg
- --bsw-fb-panel
- --bsw-fb-fg
- --bsw-fb-muted
- --bsw-fb-line
- --bsw-fb-accent
- --bsw-fb-accent-fg
- --bsw-fb-radius
.bsw-fb[data-theme="dark"] {
--bsw-fb-bg: #161714;
--bsw-fb-panel: #22241c;
--bsw-fb-fg: #f4f4ee;
--bsw-fb-muted: #b3b4aa;
--bsw-fb-line: #4a4c42;
--bsw-fb-accent: #c8ef00;
--bsw-fb-accent-fg: #161714;
--bsw-fb-radius: 12px;
}branding.primaryColor, when set, writes --bsw-fb-accent inline on the root and overrides the theme accent. className is for layout, not a second skin.
Resolve order
- If
adapteris passed, use it (BYO orcreateLocalAdapter). - Else if both
boardIdandpublishableKeyare set, use Hosted (createHostedAdapterinternally). - Else fall back to
createLocalAdapter(demo / free).
Local / demo
import { Feedback, createLocalAdapter } from "@bootstrapware/feedback";
import "@bootstrapware/feedback/styles.css";
<Feedback
user={{ id: "user_1", name: "Ada" }}
adapter={createLocalAdapter({ storageKey: "demo-feedback" })}
/>Hosted
<Feedback
boardId="brd_..."
publishableKey="bsw_live_pub_..."
user={currentUser}
/>Live config fetch needs BYO ($9.99) or Hosted ($19.99). Live Hosted writes need Hosted ($19.99). Test publishable keys work unpaid.
Limits in the UI
Title max 200 characters. Body max 5000. Statuses: open | planned | in_progress | shipped | declined. The list is 50 posts per page; Load more appears when the adapter returns nextCursor. See limits.
Similar requests
When the compose title is at least 4 characters, the widget looks for similar posts. Hosted and BYO debounce listPosts({ q }) so matches are not limited to the currently loaded page. Local mode uses in-memory substring/token overlap (no network search). Up to 3 clickable results jump to the existing post and focus Vote. Not embeddings or fuzzy NLP.
Author edit
When the adapter implements optional updatePost, the author sees Edit on their own post while its status is open. Save sends the corrected title and body with the same user.id and authorToken as submit. After staff moves the status, Edit is hidden and the text stays locked. Adapters that omit updatePost hide Edit. The control does not change status. On Local and BYO, that form also shows Remove image and Replace image. Omit imageUrl and the screenshot stays. Null clears it. A jpeg, png, or webp data URL, or an http(s) URL, replaces it (data URLs, 4 MB). Hosted hides those controls and ignores imageUrl.
When the adapter implements optional withdrawPost, the author sees Withdraw on their own open request, then Confirm withdraw. That archives the row (archivedAt). It is not a hard delete. Default lists hide it. The Hosted inbox can still restore it. Omit withdrawPost and Withdraw stays hidden. A different author, a non-open status, and an archived or merged post are rejected.
Related: Modes · Adapter · Identity · Quickstart · Limits