Ionic
Ionic chat with TalkJS: no separate SDK needed
Ionic apps run web code, so the TalkJS chat components for the web work in Ionic Angular, React and Vue. What’s specific to Ionic is small: at most one setting per flavor, push notifications, and a few Cordova or Capacitor settings. We ran the chat in Ionic React and Angular.
This is the layout of the Ionic React page we ran. The full file adds the data setup.
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Chat</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent scrollY={false}>
<Chatbox
style={{ width: '100%', height: '100%' }}
appId={appId}
userId={userId}
conversationId={conversationId}
/>
</IonContent>
</IonPage>

Which TalkJS package do I use for Ionic Angular, React or Vue?
The same one you’d use for that framework on the web: React components for Ionic React, web components for Angular and Vue. Our Ionic guide sends you to the framework getting-started guides, and those install the Components SDK. Web components also work without a framework, so a plain Ionic app uses them too. CometChat went the same way: its legacy docs call its Ionic Cordova SDK deprecated and point new Ionic apps to its JavaScript SDK.
| Ionic flavor | Install | The one setting |
|---|---|---|
| Ionic React | @talkjs/ and @talkjs/ | None |
| Ionic Angular | @talkjs/ and @talkjs/ | CUSTOM_ on the chat page’s component |
| Ionic Vue | @talkjs/ and @talkjs/ | A Vite rule that treats only t- tags as custom elements |
Every sample below uses sample_user_alice, sample_user_sebastian and sample_conversation, and the code creates them if they’re missing. Neither of the two test projects we tried had them: without that step, the console said “User sample_user_alice not found”.
Ionic React
Install the React components and the Data API, as the React getting-started guide does:
npm install @talkjs/react-components @talkjs/coreThen add a chat page. This is the page we ran:
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/react';
import { Chatbox } from '@talkjs/react-components';
import '@talkjs/react-components/default.css';
import { getTalkSession } from '@talkjs/core';
import { useEffect } from 'react';
const appId = '<APP_ID>';
const userId = 'sample_user_alice';
const otherUserId = 'sample_user_sebastian';
const conversationId = 'sample_conversation';
export default function ChatPage() {
useEffect(() => {
const session = getTalkSession({ appId, userId });
session.currentUser.createIfNotExists({ name: 'Alice' });
session.user(otherUserId).createIfNotExists({ name: 'Sebastian' });
const conversation = session.conversation(conversationId);
conversation.createIfNotExists();
conversation.participant(otherUserId).createIfNotExists();
}, []);
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Chat</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent scrollY={false}>
<Chatbox
style={{ width: '100%', height: '100%' }}
appId={appId}
userId={userId}
conversationId={conversationId}
/>
</IonContent>
</IonPage>
);
}Our code, not from the TalkJS docs; the data setup follows the React guide’s createIfNotExists pattern. We ran it in Ionic React 9.0.8 with @talkjs/ 0.3.11 on Oct 20, 2026.
scrollY={false} stops ion-content from scrolling, so only the chat’s own message list scrolls. Swap Alice and Sebastian for your own users when you wire up login.
In Chrome at phone size (390 by 844), the chat filled ion-content exactly, 788 of 788 pixels, with the composer at the bottom. Sent messages survived a reload, and a message we posted from the server as Sebastian arrived live.

More on the React side: React chat with TalkJS.
Ionic Angular
Same chat, as a web component. Install the packages from the Angular getting-started guide:
npm install @talkjs/web-components @talkjs/coreThe page is a standalone component with CUSTOM_. The Angular guide says to add it “to the @Component.schemas array of the Angular component to which you’re adding the chat,” so Angular recognizes <t-chatbox>.
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { IonContent } from '@ionic/angular/ion-content';
import { IonHeader } from '@ionic/angular/ion-header';
import { IonTitle } from '@ionic/angular/ion-title';
import { IonToolbar } from '@ionic/angular/ion-toolbar';
import '@talkjs/web-components';
import '@talkjs/web-components/default.css';
import { getTalkSession } from '@talkjs/core';
@Component({
selector: 'app-chat',
imports: [IonHeader, IonToolbar, IonTitle, IonContent],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
template: `
<ion-header>
<ion-toolbar><ion-title>Chat</ion-title></ion-toolbar>
</ion-header>
<ion-content [scrollY]="false">
<t-chatbox
style="width: 100%; height: 100%;"
[app-id]="appId"
[user-id]="userId"
[conversation-id]="conversationId"
/>
</ion-content>
`,
})
export class ChatPage {
appId = '<APP_ID>';
userId = 'sample_user_alice';
otherUserId = 'sample_user_sebastian';
conversationId = 'sample_conversation';
ngOnInit() {
const session = getTalkSession({ appId: this.appId, userId: this.userId });
session.currentUser.createIfNotExists({ name: 'Alice' });
session.user(this.otherUserId).createIfNotExists({ name: 'Sebastian' });
const conversation = session.conversation(this.conversationId);
conversation.createIfNotExists();
conversation.participant(this.otherUserId).createIfNotExists();
}
}Ours too. We ran it in Ionic Angular 9.0.8 on Oct 20, 2026, then added the data setup (the Angular guide’s pattern) and compiled it again.
The imports use Ionic 9’s per-component paths. Ionic 8 apps import from @ionic/, so import the Ionic components the way your app already does.
Two things tripped us up. First, on Angular 22 the build failed on the default.css import (TypeScript error TS2882) until we added a one-line type declaration in src/css.d.ts. That line is ours too:
declare module '*.css';Second, the page needs the ion-page class. With the component placed straight inside ion-app, the chat was 56 px tall and only its header showed. Routed through ion-router-outlet, the host element gets ion-page from Ionic and the chat filled the screen. Outside the router, add class="ion-page" to the host yourself; we only tested the routed version.
For Angular without Ionic, see Angular chat with TalkJS.
Ionic Vue
Install the same two packages as Angular, from the Vue getting-started guide:
npm install @talkjs/web-components @talkjs/coreVue needs one setting, and here Ionic Vue differs from the Vue guide. The guide’s Vite config treats every tag with a - in its name as a custom element. In Ionic Vue, that also matches ion-page, ion-content and the other Ionic tags, so Vue treats Ionic’s own tags as plain HTML and never uses the Ionic Vue components. Match only the TalkJS tags, in vite.config.ts:
import vue from '@vitejs/plugin-vue';
export default {
plugins: [
vue({
template: {
compilerOptions: {
// only TalkJS tags (t-chatbox, t-inbox, ...) are custom elements
isCustomElement: (tag) => tag.startsWith('t-'),
},
},
}),
],
};This is the Vue guide’s Vite config with one line changed, the commented one. The change is ours.
Then the page:
<script setup lang="ts">
import { IonContent, IonHeader, IonPage, IonTitle, IonToolbar } from '@ionic/vue';
import '@talkjs/web-components';
import '@talkjs/web-components/default.css';
import { getTalkSession } from '@talkjs/core';
const appId = '<APP_ID>';
const userId = 'sample_user_alice';
const otherUserId = 'sample_user_sebastian';
const conversationId = 'sample_conversation';
const session = getTalkSession({ appId, userId });
session.currentUser.createIfNotExists({ name: 'Alice' });
session.user(otherUserId).createIfNotExists({ name: 'Sebastian' });
const conversation = session.conversation(conversationId);
conversation.createIfNotExists();
conversation.participant(otherUserId).createIfNotExists();
</script>
<template>
<ion-page>
<ion-header>
<ion-toolbar><ion-title>Chat</ion-title></ion-toolbar>
</ion-header>
<ion-content :scroll-y="false">
<t-chatbox
style="width: 100%; height: 100%;"
:app-id="appId"
:user-id="userId"
:conversation-id="conversationId"
/>
</ion-content>
</ion-page>
</template>We wrote this page too. On Oct 20, 2026, we compiled it with Vue’s SFC compiler (3.5.44) under both rules. With ours, every ion- tag went through its Ionic Vue component; with the guide’s, none did.
For Vue without Ionic, see Vue.js chat with TalkJS.
Before you go live: sign user tokens
The samples above run with authentication off, which is how new TalkJS accounts start. Before launch, your server signs a JWT for each user with your secret key, and the app passes it to the session with setToken. The secret key never goes in the app. To refresh tokens, set onNeedToken once, as in this sample from the advanced authentication docs:
// You only need to set `onNeedToken` once,
// not every time you call `getTalkSession`
const session = getTalkSession({
appId: '<APP_ID>',
userId: '<USER_ID>',
});
session.onNeedToken = async () => {
// Fetch the token from your endpoint
const response = await fetch('https://<YOUR_DOMAIN>/talkjs/auth');
const token = await response.text();
// Pass it to the session
session.setToken(token);
};The authentication guide shows the server side; its example tokens expire after 24 hours. When the token flow works, turn on authentication on the Settings page of your dashboard, under Security settings.
How do I get push notifications in an Ionic app?
TalkJS sends the pushes, through Apple Push Notification service (APNs) on iOS and Firebase Cloud Messaging (FCM) on Android. Your app’s job is to get the device’s push token and register it on the TalkJS user. After that, any message sent to that user triggers a push notification when they’re offline. With Capacitor, following our push notifications guide takes three steps:
- Add your APNs and FCM credentials on the Settings page of your TalkJS dashboard, under Mobile push notifications.
- Install Capacitor’s push plugin, as its push notifications docs show:
Android needs your Firebase project’snpm install @capacitor/push-notifications npx cap syncgoogle-services.json. On iOS, enable the Push Notifications capability and add theAppDelegatelines from Capacitor’s docs. - Ask for permission, register, and hand the token to TalkJS:
Ours, built from our push guide’s token format and Capacitor’s permission flow. We type-checked it on Oct 20, 2026, withimport { Capacitor } from '@capacitor/core'; import { PushNotifications } from '@capacitor/push-notifications'; import type { TalkSession } from '@talkjs/core'; export async function registerTalkJSPush(session: TalkSession) { await PushNotifications.addListener('registration', (token) => { // Capacitor gives an APNs token on iOS and an FCM token on Android const provider = Capacitor.getPlatform() === 'ios' ? 'apns' : 'fcm'; session.currentUser.set({ pushTokens: { [`${provider}:${token.value}`]: true }, }); }); let permission = await PushNotifications.checkPermissions(); if (permission.receive === 'prompt') { permission = await PushNotifications.requestPermissions(); } if (permission.receive !== 'granted') return; await PushNotifications.register(); }@capacitor/8.1.3, but haven’t run it on a device.push-notifications
The code adds the apns: or fcm: prefix that TalkJS expects (provider:token_id). register() doesn’t ask for permission, and Android 13 needs a permission check, so requestPermissions() comes first.
When a user logs out, set their key to null so that device stops getting their notifications. This is the call from the push guide:
session.currentUser.set({
pushTokens: {
'fcm:TOKEN': null,
},
});TalkJS delivers raw push notifications, so your app decides how to show them and what a tap opens. Two limits come from Capacitor’s plugin, not from TalkJS: it doesn’t support iOS silent push, and it won’t call pushNotificationReceived for a data-only push once the app has been killed.
TalkJS also emails users who go offline and sends SMS to users with a phone number. For React Native apps, see the React Native chat page.
What changes between Capacitor and Cordova?
Both run your Ionic app’s web code in a WebView, and the chat runs there like the rest of it. The Cordova settings come from our mobile devices docs; the Capacitor tips come from Capacitor and Ionic themselves.
With Cordova
- Using the Cordova allow list, add a Content Security Policy rule that allows
https://*.talkjs.com. - If you use file sharing, also allow
https://. TalkJS uses Google Cloud for file sharing.firebasestorage.googleapis.com - Cordova opens every link inside your app by default. Install
cordova-plugin-inappbrowser, and TalkJS detects it and opens external links in the phone’s system browser.
With Capacitor
There’s no TalkJS Capacitor plugin to install. Besides the push plugin above, two tips if your chat fills the screen:
- Keyboard. Capacitor’s Keyboard plugin sets how the app resizes when the keyboard opens (iOS only).
ionicmode resizes onlyion-app;nativeresizes the whole WebView, which changes thevhunit. For full-screen apps on Android, turn onresizeOnFullScreen: an Android bug otherwise stops the keyboard from resizing the WebView. - Safe area. Per Ionic’s content docs,
ion-contentdoesn’t pad itself for the safe area, so use the--ion-safe-area-*CSS variables if your chat screen runs edge to edge.
We were able to offload all messaging to TalkJS — hugely simplifying our development of an otherwise complex stack.
Ready-made chat UI you can customize
The Components SDK gives you three pre-built chat UIs: a chatbox for one conversation, an inbox, and a conversation list. For a pop-up, put a chatbox behind your own launcher button. You style them with component props, CSS, or a custom theme.
Ionic itself ships no chat component. Its component list has the parts (ion-list, ion-item, ion-avatar, ion-textarea, ion-infinite-scroll), so a homemade chat means building the message list, bubbles and composer yourself. If you send push through FCM yourself, you also need a trusted server that stores credentials and retries failed requests.
The TalkJS Inbox shows the chat history on the left, selected conversation on the right. It's designed to act as the messaging center of your app, usually living on its own page.
The TalkJS Chatbox is the right half of the Inbox UI mode. It takes up less space and is designed to be embedded in your app near an order confirmation, a booking, or user profile.
A list of the user’s conversations. Pair it with a Chatbox to open the selected one, or use the Inbox, which has both.