Embedded Inbox

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/inbox

Demo 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

PropTypeDescription
logostringOptional logo passed to chat message UI.
rtlbooleanEnables right-to-left layout.
onConversationChange(conversation) => voidCallback when selected conversation changes.
onFiltersChange(filters) => voidCallback when list filters change.
initialFiltersConvsFiltersInitial inbox filter state.
showDetailsbooleanShow/hide details panel.
clientSectionPlaceholderReact.ReactNodeCustom content for the client section area, if it's passed it will be rendered instead of the default client section.
mobileBreakpointnumberOverride 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.
  • Inbox internally 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 id
    • token: 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>
  )
}