React component
<Comments /> is a client component. Pass the signed-in person as user and the record as scope. There is no viewerId prop. The adapter's viewerId argument is filled from user.id.
Props
user:{ id, name?, avatarUrl? }.idmax 200.namemax 120. Names are cosmetic. The id is the actor. There is no email field.scope:{ tenantKey, resourceType, resourceId }. Each field max 200. A single-tenant app still sends a stabletenantKey.appId: publishedcma_id. Local mode usescma_localwhen omitted.publishableKey:bsw_test_pub_…orbsw_live_pub_…. Together withappIdand noadapter, this selects Hosted.apiBaseUrl: defaults tohttps://comments.bootstrapware.co.adapter: aCommentsAdapter. Wins over Hosted and local.authorToken:bsw_cmauth_v1.token from your server. The widget never mints one.renewAuthorToken:() => Promise<string>. Called when unverifiedexpis under 60 seconds away, and again on an expired token, at most once every 30 seconds.permissions: button visibility when no token is present. A token'spermsreplace this list. It is not a grant. The local adapter still refusesmoderatewithout a token.searchMentionCandidatesandresolveUsers: host callbacks in every mode.layout:"threads"(default),"section", or"forum". Threads is a discussion list with flat replies (parentCommentIdstays null). Section is one chronological comment stream under the record, with nested replies and no thread list. Forum is a topic list; each topic is a nested reply tree, and resolve still closes that topic. Nested replies indent through depth 5. Depth 6 is rejected. If every section thread is resolved, a viewer withcreatecan still post a top-level comment; that starts a new implicit thread.theme:"light"or"dark". Omit it and the shell stays the light cream default. v1 does not followprefers-color-scheme.presentation:"section"(default, inline),"modal","window", or"launcher". Separate fromlayout. Modal, window, and launcher start closed unlessdefaultOpen. Escape closes them. The backdrop closes modal and launcher. Nudge the corner with--bsw-cm-frame-launcher-rightand--bsw-cm-frame-launcher-bottom.defaultOpen: open modal, window, or launcher on first render. Ignored forsection.onUnreadChange(count): fires when the unread total for the current view changes, after that view has loaded. Threads and forum sumunreadCounton the threads loaded for the active filter. Section sums the section's threads. The same callback runs for Hosted and BYO.- Comment bodies stay plain text in storage. The widget renders a small inline subset:
**bold**,_italic_or*italic*next to a letter or digit,`code`,[label](https://…), and barehttp/httpsURLs. Links userel="nofollow noopener"andtarget="_blank". Raw HTML and other schemes stay text. Mentions win when markdown would cross them. pageSize: default 50, maximum 100.dirisltrorrtl.classNameis layout only.
Resolve order
Explicit adapter, then Hosted when both appId and publishableKey are set, otherwise a memory-only local adapter. Pass createLocalAdapter({ storageKey }) when you want localStorage.
Switching user, tenant, or resource cancels in-flight requests, drops caches, closes the stream, and keeps a separate composer draft. A response for a previous tuple is ignored.
Theme tokens on .bsw-cm, or .bsw-cm[data-theme="dark"] when theme="dark": --bsw-cm-bg, --bsw-cm-panel, --bsw-cm-fg, --bsw-cm-muted, --bsw-cm-line, --bsw-cm-accent, --bsw-cm-accent-fg, --bsw-cm-radius. Published branding.primaryColor sets --bsw-cm-accent.
Full install paths: React guide.
Related: Adapter · Host themes · Modes