For AI agents: Find a documentation index at https://talkjs.com/llms.txt (full content at https://talkjs.com/llms-full.txt). Get a markdown version of any page by appending .md to its URL path.
Skip to content

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>
Dev A
Hey, I'm trying to lift state up from a child component, but I'm getting undefined errors. Any ideas?
8m ago
You
Are you passing the state and the setState function correctly as props?
6m ago
Dev A
I think so, yes.
5m ago
ok-hand
thinking
You
Maybe you're not binding the handler in the constructor. That might be the issue.
2m ago
Dev A
typing...
just now
Write a reply...
Sebastian
Hi Alice! Your ride is booked for tomorrow morning.
8:02 AM
You
Is the pickup at 9 still on?
8:02 AM
Sebastian
Yes, 9 o’clock at the front entrance.
8:04 AM
thumbs-up
Great, I’ll be outside at 9.
Classtime
Decathlon
Riot Games
Hyundai

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 flavorInstallThe one setting
Ionic React@talkjs/react-components and @talkjs/coreNone
Ionic Angular@talkjs/web-components and @talkjs/coreCUSTOM_ELEMENTS_SCHEMA on the chat page’s component
Ionic Vue@talkjs/web-components and @talkjs/coreA 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/core

Then 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/react-components 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.

An Ionic page with a toolbar titled Chat and a TalkJS chatbox below it. Sebastian says “Hi Alice! Your ride is booked for tomorrow morning.” and Alice replies “Is the pickup at 9 still on?”. The message composer sits at the bottom of the screen.
The Ionic React page above in Chrome at phone size, October 2026.

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

The page is a standalone component with CUSTOM_ELEMENTS_SCHEMA. 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/angular/standalone, 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/core

Vue 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:

  1. Add your APNs and FCM credentials on the Settings page of your TalkJS dashboard, under Mobile push notifications.
  2. Install Capacitor’s push plugin, as its push notifications docs show:
    npm install @capacitor/push-notifications
    npx cap sync
    Android needs your Firebase project’s google-services.json. On iOS, enable the Push Notifications capability and add the AppDelegate lines from Capacitor’s docs.
  3. Ask for permission, register, and hand the token to TalkJS:
    import { 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();
    }
    Ours, built from our push guide’s token format and Capacitor’s permission flow. We type-checked it on Oct 20, 2026, with @capacitor/push-notifications 8.1.3, but haven’t run it on a device.

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

  1. Using the Cordova allow list, add a Content Security Policy rule that allows https://*.talkjs.com.
  2. If you use file sharing, also allow https://firebasestorage.googleapis.com. TalkJS uses Google Cloud for file sharing.
  3. 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). ionic mode resizes only ion-app; native resizes the whole WebView, which changes the vh unit. For full-screen apps on Android, turn on resizeOnFullScreen: an Android bug otherwise stops the keyboard from resizing the WebView.
  • Safe area. Per Ionic’s content docs, ion-content doesn’t pad itself for the safe area, so use the --ion-safe-area-* CSS variables if your chat screen runs edge to edge.
Retreat Guru logo
We were able to offload all messaging to TalkJS — hugely simplifying our development of an otherwise complex stack.
Deryk Wenaus
CTO, Retreat Guru

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.

Inbox

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.

Chatbox

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.

Conversation list

A list of the user’s conversations. Pair it with a Chatbox to open the selected one, or use the Inbox, which has both.

FAQs

Front end. Ionic is a front-end framework: it builds your app’s screens, which run as web code inside a WebView on the phone. It doesn’t store or deliver messages. In an Ionic chat app, TalkJS is the backend: we store the messages, deliver them to everyone in the conversation, and notify users who are offline by email, SMS and push.

The same as for any other app. Every plan includes a free development mode with no time limit, so you can build and test first. Basic is $279 a month, or $239 a month billed annually, with 10,000 monthly active users included. Email, SMS and push are on every plan; SMS messages are billed separately. See pricing for the other plans.