Embedded Inbox (React)
Open in the app: Embedded Inbox (opens in a new tab)
You can embed Bread Crumbs Inbox directly inside your React application using the exported Inbox component.
Install
npm install @bcrumbs.net/inboxDemo repository
For a full working example, see the demo project:
embedded-inbox-demo (opens in a new tab)
What this gives you
- Conversation list + chat + details in one component
- Desktop and mobile layouts out of the box
- Tags, and assignment-aware UI
- Start conversation and add-contact flows built in
Import
import { Inbox } from '@bcrumbs.net/inbox'Basic usage
import React from 'react'
import { Inbox } from '@bcrumbs.net/inbox'
export default function EmbeddedInboxPage() {
return (
<div style={{ height: '100vh' }}>
<Inbox />
</div>
)
}Props
| Prop | Type | Description |
|---|---|---|
| logo | string | Optional logo passed to chat message UI. |
| rtl | boolean | Enables right-to-left layout. |
| onConversationChange | (conversation) => void | Callback when selected conversation changes. |
| onFiltersChange | (filters) => void | Callback when list filters change. |
| initialFilters | ConvsFilters | Initial inbox filter state. |
| showDetails | boolean | Show/hide details panel. |
| clientSectionPlaceholder | React.ReactNode | Custom content for the client section area, if it's passed it will be rendered instead of the default client section. |
| mobileBreakpoint | number | Override the breakpoint used for mobile layout. |
Layout behavior
- Desktop: list + chat + optional details panel
- Mobile: internal view switching (list/chat/details)
- Details panel can be toggled open/closed (desktop, when enabled)
Requirements / notes
- The component expects the authenticated workspace context to be available.
- Make sure your app provides the same auth/session context used by Bread Crumbs clients.
Inboxinternally uses data clients and periodic fetching, so mount it inside a stable page container with explicit height.
Usage guidelines
Important integration notes you should apply in production:
- Initialize i18n (
i18next+react-i18next) and provide translations used by Inbox. - Use ApolloProvider and configure the GraphQL clients required by the Inbox flow.
- Wrap Inbox with ThemeProvider from
@bcrumbs.net/inbox. - Use Radix Theme in your app, because Inbox uses Radix UI components.
- Load required shared styles (constants/themes/icons) so the component renders correctly.
- Prepare localStorage values before render:
ContextId: workspace idtoken: API key used for authorization
- File upload support may require Azure Blob dependencies/configuration in your build setup.
Example with callbacks and filters
import { useEffect, useState } from 'react'
import { Inbox } from '@bcrumbs.net/inbox'
import { setErrorHandler } from '@bcrumbs.net/bc-api'
import { ServerError } from '@apollo/client'
setErrorHandler(({ networkError, graphQLErrors }) => {
if (networkError && (networkError as ServerError).statusCode === 401) {
console.log('The token is expired or invalid, please get a new token.')
}
if (
networkError &&
(networkError as ServerError).statusCode > 500 &&
(networkError as ServerError).statusCode !== 503
) {
console.log('The server is down, please try again later.')
}
if (graphQLErrors?.find((error) => error?.extensions?.['code'] === 'FORBIDDEN')) {
console.log('The token is expired or invalid, please get a new token.')
}
})
export default function SupportInbox() {
const [isStorageReady, setIsStorageReady] = useState(false)
const [filters, setFilters] = useState({ ended: false })
useEffect(() => {
// Provide your workspace context and auth token before mounting Inbox
localStorage.setItem('ContextId', '<YOUR_WORKSPACE_ID>')
localStorage.setItem('token', '<YOUR_API_TOKEN>')
setIsStorageReady(true)
}, [])
if (!isStorageReady) return null
return (
<div style={{ height: 'calc(100vh - 64px)' }}>
<Inbox
showDetails={true}
rtl={false}
mobileBreakpoint={1000}
initialFilters={filters}
onConversationChange={(conv) => {
console.log('Selected conversation:', conv.id)
}}
onFiltersChange={(filters) => {
console.log('Inbox filters:', filters)
setFilters(filters)
}}
logo="https://example.com/logo.png"
clientSectionPlaceholder={<div>Client Section</div>}
/>
</div>
)
}