Getting started: Chat UI Components with React
This guide shows you how to add Ably Chat React UI Components to a brand-new React app built with Vite.
You will:
- Create an Ably realtime client and Chat client
- Install the ready-made UI component package
- Build up a complete chat interface component by component
- Customise look and feel with your own styles
- Add your own chat settings and avatars
Prerequisites
-
Sign up for an Ably account.
-
Create an app and copy its API key (the root key is fine while you experiment).
-
Install the Ably CLI:
npm install -g @ably/cli
- Log in and set the default app/key:
ably login
ably apps switch
ably auth keys switch
Create a new project
- Scaffold a React + TypeScript project with Vite:
npm create vite@latest my-chat-ui-app -- --template react-ts
cd my-chat-ui-app
- (Optional) Add Tailwind CSS if you want utility classes elsewhere in your app. The UI kit itself ships pre-compiled CSS, so Tailwind isn't required:
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Follow the Tailwind Vite guide to configure the generated files.
- Install the Chat UI kit and its peers:
npm install ably @ably/chat @ably/chat-react-ui-components
# Ensure React 19 is present (Vite template already has these)
npm install react react-dom
That's all the setup you need—the kit's CSS is automatically bundled by Vite alongside the rest of your styles.
Usage
The components and their stylesheet can be imported into your React applications like so:
1
2
3
// App.tsx
import { App, ChatWindow, Sidebar, RoomInfo, AppLayout } from '@ably/chat-react-ui-components';
import '@ably/chat-react-ui-components/dist/styles.css';
The @ably/chat-react-ui-components/dist/styles.css
file contains all the necessary styles for the components, compiled from the Tailwind utility classes used in the component code.
Providers setup
ably-chat-react-ui-components relies on the same React context providers as the underlying Chat SDK, plus a few extras for theming and avatars.
Basic provider setup
In your main entry file (e.g. main.tsx
), replace the content with the following code to set up the providers:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// main.tsx
import * as Ably from 'ably';
import { ChatClient } from '@ably/chat';
import { ChatClientProvider } from '@ably/chat/react';
import { ThemeProvider, AvatarProvider, ChatSettingsProvider } from '@ably/chat-react-ui-components';
import '@ably/chat-react-ui-components/dist/style.css';
// Create Ably Realtime client
const ablyClient = new Ably.Realtime({
key: '{{API_KEY}}', // Replace with your Ably API key
clientId: 'your-chat-client-id',
});
const chatClient = new ChatClient(ablyClient);
ReactDOM.createRoot(document.querySelector('#root') || document.createElement('div')).render(
<React.StrictMode>
<ThemeProvider>
<AvatarProvider>
<ChatSettingsProvider>
<ChatClientProvider client={chatClient}>
{/* Your components will go here */}
</ChatClientProvider>
</ChatSettingsProvider>
</AvatarProvider>
</ThemeProvider>
</React.StrictMode>
);
The components you make throughout this guide will be wrapped in these providers to ensure they have access to the necessary context.
Provider responsibilities
ChatClientProvider
– supplies the Ably Chat client so child components can publish, subscribe, and manage roomsThemeProvider
– toggles light/dark mode and optionally stores the preference (persist: true
)AvatarProvider
– generates and caches user / room avatarsChatSettingsProvider
– provides a place to store and retrieve chat settings that control the UI, such as enabling message editing or reactionsChatRoomProvider
– provides the chat room context for components that operate on a specific room, such as theChatWindow
,TypingIndicators
andRoomInfo
components
Building your chat interface
Let's build up a complete chat interface step by step, starting with individual components and working up to a full application.
ChatWindow component
The ChatWindow
component provides the main chat interface for a room.
It handles everything related to messages - display, editing, deletion, reactions, history and real-time updates.
Features:
- Message display with history loading and infinite scroll
- Message editing, deletion, and reactions
- Typing indicators and presence awareness
- Custom header and footer content areas
- Discontinuity recovery on reconnection
- Configurable message window size for performance
Requirements: Must be wrapped in ChatRoomProvider
, AvatarProvider
, and ChatSettingsProvider
. The settings provider controls which message actions (update/delete/react) are available.
Create a simple file called App.tsx
with the following content:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import { ChatWindow } from '@ably/chat-react-ui-components';
import { ChatRoomProvider } from '@ably/chat/react';
export function ChatApp() {
return (
<div className="bg-gray-50 rounded-lg border">
<div
className="overflow-hidden border rounded-lg flex"
style={{ width: '70vw', height: '70vh' }}
>
<ChatRoomProvider name="my-first-room">
<ChatWindow roomName="my-first-room" enableTypingIndicators={true} />
</ChatRoomProvider>
</div>
</div>
);
}
Now import the ChatApp
component in your main.tsx
file and render it within the providers:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// main.tsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import * as Ably from 'ably';
import { ChatClient } from '@ably/chat';
import { ChatClientProvider } from '@ably/chat/react';
import { ThemeProvider, AvatarProvider, ChatSettingsProvider } from '@ably/chat-react-ui-components';
import '@ably/chat-react-ui-components/dist/style.css';
import { ChatApp } from './App.tsx'; // Assuming your app.tsx is in the same directory
const ablyClient = new Ably.Realtime({
key: '{{API_KEY}}', // Replace with your Ably API key
clientId: 'your-chat-client-id',
});
const chatClient = new ChatClient(ablyClient);
ReactDOM.createRoot(document.querySelector('#root') || document.createElement('div')).render(
<React.StrictMode>
<ThemeProvider>
<AvatarProvider>
<ChatSettingsProvider>
<ChatClientProvider client={chatClient}>
<ChatApp />
</ChatClientProvider>
</ChatSettingsProvider>
</AvatarProvider>
</ThemeProvider>
</React.StrictMode>
);
Typing indicators are enabled by default, but you can disable them by setting enableTypingIndicators={false}
.
Try sending a message to the room, use the following command:
ably rooms messages send my-first-room "Hello, world!" --clientId your-chat-client-id
To simulate typing in the room, use the following command:
ably rooms typing keystroke my-first-room --clientId your-chat-client-id
Adding Room Information
The RoomInfo
component displays comprehensive information about a chat room. It shows the room avatar, live presence count, participant details, and typing indicators.
Features:
- Room avatar display with automatic generation
- Live presence count badge showing active participants
- Interactive hover tooltip with participant preview
- Expandable participant list with detailed user information
- In-place avatar with color and image customization via the
AvatarProvider
- Typing indicators built-in
- Accessibility support with ARIA roles and keyboard navigation
Requirements: Must be wrapped in both ChatRoomProvider
and AvatarProvider
.
Let's add the RoomInfo component to our chat window's header section, replace the content in App.tsx
with the following code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// App.tsx
import { ChatWindow, RoomInfo } from '@ably/chat-react-ui-components';
import { ChatRoomProvider } from '@ably/chat/react';
export function ChatApp() {
return (
<div className="bg-gray-50 rounded-lg border">
<div
className="overflow-hidden border rounded-lg flex"
style={{ width: '70vw', height: '70vh' }}>
<ChatRoomProvider name="my-first-room">
<ChatWindow
roomName="my-first-room"
customHeaderContent={<RoomInfo />}
/>
</ChatRoomProvider>
</div>
</div>
);
}
The RoomInfo
component will automatically display the room avatar, participant count, and typing indicators. You can customize its appearance by passing props like roomAvatar
, position
, and className
.
1
2
3
4
5
6
7
8
9
10
11
12
13
<RoomInfo
// Optional custom avatar data (overrides AvatarProvider)
roomAvatar={{
displayName: 'VIP Lounge',
color: 'bg-green-500',
initials: 'VL',
src: 'https://example.com/vip-avatar.jpg',
}}
// Position for dropdown menus
position={{ top: 60, left: 250 }}
// Custom styling
className="p-4 bg-blue-400 rounded-lg shadow-sm"
/>
For now we will just use the defaults for the RoomInfo
component.
Try using the Ably CLI to enter the rooms presence set, you should see this reflected in the RoomInfo component:
ably rooms presence enter my-first-room --clientId your-chat-client-id
You can also use the CLI to simulate typing in the room too, which will show up in the RoomInfo component's typing indicators:
ably rooms typing keystroke my-first-room --clientId your-chat-client-id
Adding Room Reactions
The chat window also supports custom footer content, which can be used for additional controls like reactions. You can pass any React component as customFooterContent
, e.g., the RoomReaction
component.
To add the RoomReaction
component, update your App.tsx
file as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// App.tsx
import { ChatWindow, RoomInfo, RoomReaction } from '@ably/chat-react-ui-components';
import { ChatRoomProvider } from '@ably/chat/react';
export function ChatApp() {
return (
<div className="bg-gray-50 rounded-lg border">
<div
className="overflow-hidden border rounded-lg flex"
style={{ width: '70vw', height: '70vh' }}>
<ChatRoomProvider name="my-first-room">
<ChatWindow
roomName="my-first-room"
customHeaderContent={<RoomInfo />}
customFooterContent={<RoomReaction />}
/>
</ChatRoomProvider>
</div>
</div>
);
}
Now try sending a thumbs up reaction to the room using the Ably CLI:
ably rooms reactions send my-first-room 👍 --clientId your-chat-client-id
You should see the reaction appear on the screen as a small explosion animation.
Adding a Sidebar
Now let's add a Sidebar component to our chat application. The Sidebar provides room navigation and management, allowing users to create, join, and leave rooms. It can be placed next to the ChatWindow to provide a complete chat interface.
Features:
- Collapsible interface with avatar-only mode
- Room creation and management
- Theme toggle integration
- Active room highlighting
- Room count display
- Automatic room attachment/detachment
The sidebar automatically manages room connections as users navigate. It also uses occupancy events to provide context about connected and present users in each room.
To add the Sidebar component, update your App.tsx
file as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
// App.tsx
import { ChatWindow, RoomInfo, RoomReaction, Sidebar } from '@ably/chat-react-ui-components';
import { ChatRoomProvider } from '@ably/chat/react';
import { type RoomOptions } from '@ably/chat';
import { useState, useCallback } from 'react';
const DEFAULT_ROOM_OPTIONS: RoomOptions = {
occupancy: { enableEvents: true },
};
export function ChatApp() {
const [roomNames, setRoomNames] = useState<string[]>(['my-first-room', 'general', 'random']);
const [activeRoom, setActiveRoom] = useState<string | undefined>('my-first-room');
const [isSidebarCollapsed, setIsSidebarCollapsed] = useState(false);
const addRoom = useCallback((name: string) => {
setRoomNames((prev) => (prev.includes(name) ? prev : [...prev, name]));
setActiveRoom(name);
}, []);
const leaveRoom = useCallback(
(name: string) => {
setRoomNames((prev) => {
const next = prev.filter((n) => n !== name);
if (next.length === 0) {
setActiveRoom('');
} else if (name === activeRoom) {
setActiveRoom(next[0]);
}
return next;
});
},
[activeRoom],
);
return (
<div className="bg-gray-50 rounded-lg border">
<div className="overflow-hidden border rounded-lg flex" style={{width: '70vw', height: '70vh'}}>
{/* Sidebar */}
<div className={`flex-shrink-0 ${isSidebarCollapsed ? 'w-16' : 'w-64'}`}>
<Sidebar
roomNames={roomNames}
activeRoomName={activeRoom}
addRoom={addRoom}
defaultRoomOptions={DEFAULT_ROOM_OPTIONS}
setActiveRoom={setActiveRoom}
leaveRoom={leaveRoom}
isCollapsed={isSidebarCollapsed}
onToggleCollapse={() => setIsSidebarCollapsed(prev => !prev)}
/>
</div>
{/* Chat Window */}
<div className="flex-1 overflow-hidden">
{activeRoom ? (
<ChatRoomProvider
key={activeRoom}
name={activeRoom}
attach={false}
release={false}
options={DEFAULT_ROOM_OPTIONS}
>
<ChatWindow
roomName={activeRoom}
customHeaderContent={<RoomInfo />}
customFooterContent={<RoomReaction />}
/>
</ChatRoomProvider>
) : (
<div className="flex items-center justify-center h-full">
<p>Select a room to start chatting</p>
</div>
)}
</div>
</div>
</div>
);
}
Now we have a complete chat interface with a sidebar for room navigation and a chat window for messaging.
App component
Finally, if you prefer a ready-to-use solution, the library provides an App
component that combines all the components above with sensible defaults. This is great if you need to prototype quickly or see how everything fits together.
Features:
- Manages room state (adding, leaving, selecting rooms)
- Shows loading state when not connected
- Renders layout with Sidebar and ChatWindow
- Includes RoomInfo in header and RoomReaction in footer
- Handles connection status and error states
To use the App
component, import it in your main.tsx
file and render it within the providers:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// main.tsx
import * as Ably from 'ably';
import { ChatClient } from '@ably/chat';
import { ChatClientProvider } from '@ably/chat/react';
import React from 'react';
import ReactDOM from 'react-dom/client';
import {
App,
ThemeProvider,
AvatarProvider,
ChatSettingsProvider
} from '@ably/chat-react-ui-components';
import '@ably/chat-react-ui-components/dist/style.css';
// Create Ably Realtime client
const ablyClient = new Ably.Realtime({
key: '{{API_KEY}}',
clientId: 'your-chat-client-id',
});
const chatClient = new ChatClient(ablyClient);
ReactDOM.createRoot(document.querySelector('#root') || document.createElement('div')).render(
<React.StrictMode>
<ThemeProvider options={{ persist: true, defaultTheme: 'light' }}>
<AvatarProvider>
<ChatSettingsProvider>
<ChatClientProvider client={chatClient}>
<App initialRoomNames={"my-first-room"}/>
</ChatClientProvider>
</ChatSettingsProvider>
</AvatarProvider>
</ThemeProvider>
</React.StrictMode>
);
You should now see a fully functional chat application with a sidebar, chat window, room info, and reactions and an initial room already created.
Summary
The components are designed to be flexible and composable, allowing you to mix and match them as needed. You can also customize appearance and behavior using the context providers like ThemeProvider
, AvatarProvider
, and ChatSettingsProvider
.
You can use the individual components like RoomInfo
, ChatWindow
, and Sidebar
to create custom layouts and functionality, or you can use the complete App
component for rapid prototyping of a full chat application.
The UI components are experimental and are highly likely to change in future releases.
Next steps
Continue exploring Ably Chat UI components:
- Read more about using rooms and sending messages.
- Find out more regarding presence.
- Understand how to use typing indicators.
- Send reactions to your rooms.
- Read into pulling messages from history and providing context to new joiners.
- Understand token authentication before going to production.
Explore the Ably CLI further, or check out the Chat JS API references for additional functionality.