RealTimeX
Sign inStart for free
RealTimeXMobile Package
Introduction5-minute overviewFeaturesHow the package worksGlossary
Requirements & dependenciesBackend credentialsInstallation step by stepTutorial — your first chat appProject config fileApp entry — index.jsQuick start — minimum working chatComplete ChatScreen example
Native configuration (iOS & Android)Firebase, APNs & backend setup
Navigation — embedding the chatSession, auth & Socket.IOPermissions & access controlAudio & video callingPush notificationsMentions viewRich-text messages (WebView editor)Total unread count
Customization — four waysDefault component fallback (important)Which slots are wiredCustomization examples (Case 1–4)UI feature flags & copy (ui)Chat info (group + DM)Style overrides (ui.styles)Render props (ChatProvider)Theme, fonts & appearance
ChatProvider props referenceconfigureChat options referenceHooks & storeCallbacks referenceAPI query paramsAll exports
Production integration pattern (Fieldr)Host app integration — providers, toasts, tab bars & navigationEnvironment variablesLocal package / monorepo (Metro)
TroubleshootingSetup checklistArchitectureDocumentation & file mapPackage development (maintainers)License
Mobile packageCustomization

Default component fallback (important)

Customization is opt-in per slot. You never need to register every component.

How it works internally

code
1configureChat({ ui: { components: { MessageBubble: MyBubble } } })2        ↓3runtime.config merges your partial over DEFAULT_CHAT_UI (components: {})4        ↓5At render:  getUiConfig().components.MessageBubble || MessageBubble6        ↓7Custom passed?  → MyBubble8Not passed?     → package MessageBubble (built-in default)

Rules:

You passResult
No ui at allFull default chat UI
ui.components = { MessageBubble: MyBubble }Custom bubble only; all other slots use defaults
ui.components = { MessageBubble: undefined }Treated as not passed → default bubble
ui.styles.message.sender.bubble = {...}Your style merges on top of the built-in style
ui.chatRoom.messageActions = { forward: false }Only forward changes; other actions keep true
A render prop (e.g. renderHeader)Replaces that area whenever it is passed — returning null renders nothing

Code pattern inside the package

Every wired slot follows this pattern (src/screen/chat/ChatRoomScreen.tsx):

tsx
1const ComposerComponent = ui.components.MessageComposer || MessageComposer;2const HeaderComponent = ui.components.ChatRoomHeader || ChatRoomHeader;

Your component receives the same props as the package default. Import the prop type (MessageBubbleProps, MessageComposerProps, ChatRoomHeaderProps, ConversationListItemProps) from the package.

Wrapping instead of rebuilding

The defaults are exported — wrap them when you only need extra layout or styling:

tsxsrc/chat/custom/MyBubble.tsx
1// src/chat/custom/MyBubble.tsx2import React from 'react';3import {View} from 'react-native';4import {MessageBubble, type MessageBubbleProps} from '@realtimexsco/live-chat-react-native';5 6export const MyBubble = (props: MessageBubbleProps) => (7  <View style={{paddingHorizontal: 4}}>8    <MessageBubble {...props} />9  </View>10);

Note

Inside a replacement for slot X, render the exported built-in X — not getUiConfig().components.X, which points back to your own component (infinite recursion).
PreviousCustomization — four waysNextWhich slots are wired

On this page

How it works internallyCode pattern inside the packageWrapping instead of rebuilding
Back to top