npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ethora/chat-component

v26.1.2

Published

1. npm create vite@latest 2. select name of project, select type (react/js) 3. cd project-name 4. npm i 5. npm i @ethora/chat-component 6. go to file src/App.tsx and replace it with this code

Readme

Ethora Chat Component (@ethora/chat-component)

GitHub watchers GitHub forks GitHub Repo stars GitHub repo size GitHub language count GitHub top language GitHub commit activity (branch) GitHub issues GitHub closed issues GitHub GitHub contributors

JavaScript React TypeScript JWT

Discord Twitter URL Website YouTube Channel Subscribers

React + TypeScript chat UI component powered by Ethora backend APIs and XMPP.
Use it as a standalone chat page, as an embedded widget in your existing app, or as a customizable chat foundation with your own auth and UI.

Table of Contents

Overview

@ethora/chat-component gives you a production-oriented chat interface with:

  • Room list and room chat UI
  • Message history, replies, reactions, edits, deletes
  • Typing indicators
  • In-app notifications + Web Push integration
  • Configurable auth modes (default/login form/google/jwt/custom user)
  • Custom render components for message/input/scroll/day separator/new-message label

The package exports:

  • Chat (main component)
  • XmppProvider
  • useUnread
  • logoutService
  • useQRCodeChat, handleQRChatId
  • useInAppNotifications
  • usePushNotifications
  • resendMessage

Why Ethora

Ethora provides hosted and customizable messaging infrastructure plus a wider product ecosystem.

| Dimension | Ethora Chat Component | Full Ethora Platform | | --- | --- | --- | | Primary goal | Embed chat quickly in a React app | End-to-end product stack (chat, profiles, wallets, AI, admin) | | Time to first chat | Minutes | Higher initial setup, broader capabilities | | Frontend scope | Focused web chat UI package | Multi-product ecosystem and broader SDK/tooling | | Custom UI control | High via props + custom components | High, with additional platform-specific tooling | | Best fit | Support chat, portal messaging, embedded chat widget | Full social/messaging app platforms with extended modules |

Quick Start

1. Install

| Tool | Command | | --- | --- | | npm | npm i @ethora/chat-component | | yarn | yarn add @ethora/chat-component | | pnpm | pnpm add @ethora/chat-component | | bun | bun add @ethora/chat-component |

2. Render the chat

import { Chat, XmppProvider } from '@ethora/chat-component';
import './App.css';

export default function App() {
  return (
    <XmppProvider>
      <Chat />
    </XmppProvider>
  );
}

Required wrapper (XmppProvider)

Chat relies on internals that use useXmppClient(). In real integrations, wrap Chat (or your entire app shell) with XmppProvider:

import { Chat, XmppProvider } from '@ethora/chat-component';

export default function App() {
  return (
    <XmppProvider>
      <Chat config={{ baseUrl: 'https://api.ethoradev.com/v1' }} />
    </XmppProvider>
  );
}

3. Run

npm run dev

Open http://localhost:5173.

Integration Modes

All modes below assume XmppProvider wraps Chat.

A) Minimal demo mode (provider + chat)

<XmppProvider>
  <Chat />
</XmppProvider>

Useful for local proof-of-concept and quick UI validation.

B) Auto default credential fallback (legacy behavior)

If no googleLogin, no jwtLogin, no userLogin, and no defaultLogin, LoginWrapper currently triggers internal email/password fallback logic.

<XmppProvider>
  <Chat config={{ colors: { primary: '#2563eb', secondary: '#dbeafe' } }} />
</XmppProvider>

C) Explicit email/password via user prop

<XmppProvider>
  <Chat
    user={{
      email: '[email protected]',
      password: 'PLACEHOLDER_PASSWORD',
    }}
  />
</XmppProvider>

D) Injected logged-in user (userLogin)

<XmppProvider>
  <Chat
    config={{
      userLogin: {
        enabled: true,
        user: {
          _id: 'PLACEHOLDER_USER_ID',
          appId: 'PLACEHOLDER_APP_ID',
          walletAddress: 'PLACEHOLDER_WALLET_ADDRESS',
          defaultWallet: { walletAddress: 'PLACEHOLDER_WALLET_ADDRESS' },
          firstName: 'Jane',
          lastName: 'Doe',
          xmppPassword: 'PLACEHOLDER_XMPP_PASSWORD',
          token: 'PLACEHOLDER_ACCESS_TOKEN',
          refreshToken: 'PLACEHOLDER_REFRESH_TOKEN',
          username: 'PLACEHOLDER_USERNAME',
        },
      },
    }}
  />
</XmppProvider>

E) JWT login

<XmppProvider>
  <Chat
    config={{
      jwtLogin: {
        enabled: true,
        token: 'PLACEHOLDER_JWT_TOKEN',
      },
    }}
  />
</XmppProvider>

F) Google login

<XmppProvider>
  <Chat
    config={{
      googleLogin: {
        enabled: true,
        firebaseConfig: {
          apiKey: 'PLACEHOLDER_API_KEY',
          authDomain: 'PLACEHOLDER_AUTH_DOMAIN',
          projectId: 'PLACEHOLDER_PROJECT_ID',
          storageBucket: 'PLACEHOLDER_STORAGE_BUCKET',
          messagingSenderId: 'PLACEHOLDER_MESSAGING_SENDER_ID',
          appId: 'PLACEHOLDER_APP_ID',
        },
      },
    }}
  />
</XmppProvider>

G) Single-room entry + URL/QR behavior

<XmppProvider>
  <Chat
    roomJID="[email protected]"
    config={{
      setRoomJidInPath: true,
      qrUrl: 'https://your-app.example/chat/?qrChatId=',
    }}
  />
</XmppProvider>

roomJID forces entry room.
setRoomJidInPath syncs room identity to URL path.
useQRCodeChat / handleQRChatId support QR/deep-link room opening.

Behavior Notes and Legacy Quirks

  • newArch is now default-on. If omitted, runtime uses new architecture paths.
  • Old architecture is used only when you explicitly set config.newArch = false.
  • defaultLogin currently has legacy inverted behavior in LoginWrapper:
    • internal fallback login runs when login modes are not configured and defaultLogin is not set.
    • keep this in mind when migrating; prefer explicit userLogin / jwtLogin / googleLogin.

Chat Props Reference

These are the top-level props accepted by Chat (exported from ReduxWrapper).

| Prop | Type | Required | Notes | | --- | --- | --- | --- | | config | IConfig | No | Main behavior/configuration object. | | roomJID | string | No | Force specific room JID on load. | | user | { email: string; password: string } | No | Credentials for email/password login helper path. | | loginData | { email: string; password: string } | No | Optional login payload. | | MainComponentStyles | React.CSSProperties | No | Outer container style override. | | token | string | No | Optional token input (legacy/integration-specific usage). | | CustomMessageComponent | React.ComponentType<MessageProps> | No | Replace message bubble rendering. | | CustomInputComponent | React.ComponentType<SendInputProps & { onSendMessage?; onSendMedia?; placeholderText?; }> | No | Replace chat input area. | | CustomScrollableArea | React.ComponentType<CustomScrollableAreaProps> | No | Replace list/scroll wrapper behavior. | | CustomDaySeparator | React.ComponentType<DaySeparatorProps> | No | Replace day separator node. | | CustomNewMessageLabel | React.ComponentType<NewMessageLabelProps> | No | Replace "new message" marker. |

Full Config Reference (IConfig)

Below is a grouped reference for all config options.

Core

| Option | Type | Description | | --- | --- | --- | | appId | string | App identifier for backend context. | | baseUrl | string | API base URL (default project uses https://api.ethoradev.com/v1). | | customAppToken | string | Custom app token for API initialization. | | xmppSettings | { devServer; host; conference?; xmppPingOnSendEnabled? } | XMPP connectivity settings. | | initBeforeLoad | boolean | Initialize XMPP before normal chat load flow. | | clearStoreBeforeInit | boolean | Clear local store before initialization. | | newArch | boolean | Defaults to true; set false to explicitly force legacy/old architecture paths. | | useStoreConsoleEnabled | boolean | Enable verbose internal logging in console. |

UI and Layout

| Option | Type | Description | | --- | --- | --- | | disableHeader | boolean | Hide chat header. | | disableMedia | boolean | Disable media sending/processing paths. | | disableRooms | boolean | Hide/disable room list area. | | disableRoomMenu | boolean | Disable room menu controls. | | disableRoomConfig | boolean | Disable room configuration actions. | | disableNewChatButton | boolean | Hide new chat/create room action. | | disableUserCount | boolean | Hide user count in header/UI. | | disableChatInfo | { disableHeader?; disableDescription?; disableType?; disableMembers?; hideMembers?; disableChatHeaderMenu? } | Fine-grained chat info panel toggles. | | chatHeaderBurgerMenu | boolean | Toggle burger menu in chat header. | | chatHeaderSettings | { hide?; disableCreate?; disableMenu?; hideSearch? } | Additional header-level controls. | | chatHeaderAdditional | { enabled: boolean; element: any } | Inject custom element into header area. | | headerLogo | string \| React.ReactElement | Custom logo in header. | | headerMenu | () => void | Custom menu handler. | | headerChatMenu | () => void | Custom room header menu handler. | | colors | { primary: string; secondary: string } | Theme colors for component UI. | | roomListStyles | React.CSSProperties | Styles for room list pane. | | chatRoomStyles | React.CSSProperties | Styles for chat pane. | | backgroundChat | { color?: string; image?: string \| File } | Chat background customization. | | bubleMessage | MessageBubble | Bubble-level style overrides (as defined in types). | | setRoomJidInPath | boolean | Sync room JID to URL path. | | qrUrl | string | Base URL for QR deep link behavior. |

Auth and Identity

| Option | Type | Description | | --- | --- | --- | | defaultLogin | boolean | Legacy quirk: current runtime fallback behavior is inverted; see Behavior Notes section. | | googleLogin | { enabled: boolean; firebaseConfig: FBConfig } | Google login support via Firebase config. | | jwtLogin | { token: string; enabled: boolean; handleBadlogin?: React.ReactElement } | Log user in using JWT exchange flow. | | userLogin | { enabled: boolean; user: User \| null } | Inject already-authenticated user directly. | | customLogin | { enabled: boolean; loginFunction: () => Promise<User \| null> } | Provide your custom async login function. | | refreshTokens | { enabled: boolean; refreshFunction?: () => Promise<{ accessToken: string; refreshToken?: string } \| null> } | Token refresh strategy. |

Rooms and Data

| Option | Type | Description | | --- | --- | --- | | defaultRooms | ConfigRoom[] | Seed/default rooms. | | customRooms | { rooms: PartialRoomWithMandatoryKeys[]; disableGetRooms?: boolean; singleRoom: boolean } | Fully controlled room source. | | forceSetRoom | boolean | Force room setup path in init flow. | | enableRoomsRetry | { enabled: boolean; helperText: string } | Enable retry UX when rooms fail to load. |

Messaging and Interactions

| Option | Type | Description | | --- | --- | --- | | disableInteractions | boolean | Disable message interaction menu/actions. | | disableProfilesInteractions | boolean | Disable profile interactions from chat UI. | | disableSentLogic | boolean | Disable default sent-state logic when needed. | | secondarySendButton | { enabled: boolean; messageEdit: string; label?: React.ReactNode; buttonStyles?: React.CSSProperties; hideInputSendButton?: boolean; overwriteEnterClick?: true } | Extra send action/button config. | | botMessageAutoScroll | boolean | Force auto-scroll behavior on bot messages. | | messageTextFilter | { enabled: boolean; filterFunction: (text: string) => string } | Transform/filter outgoing message text. | | eventHandlers | { onMessageSent?; onMessageFailed?; onMessageEdited? } | Lifecycle callbacks for message operations. | | translates | { enabled: boolean; translations?: Iso639_1Codes } | Message translation-related options. | | whitelistSystemMessage | string[] | Restrict/render only selected system message types. | | customSystemMessage | React.ComponentType<MessageProps> | Replace system message component renderer. |

Typing and Sending Control

| Option | Type | Description | | --- | --- | --- | | disableTypingIndicator | boolean | Disable typing indicator UI logic. | | customTypingIndicator | { enabled: boolean; text?: string \| ((usersTyping: string[]) => string); position?: 'bottom' \| 'top' \| 'overlay' \| 'floating'; styles?: React.CSSProperties; customComponent?: React.ComponentType<{ usersTyping: string[]; text: string; isVisible: boolean; }> } | Customize typing indicator content and rendering. | | blockMessageSendingWhenProcessing | boolean \| { enabled: boolean; timeout?: number; onTimeout?: (roomJID: string) => void } | Gate sends while processing in-flight state. |

Notifications

| Option | Type | Description | | --- | --- | --- | | inAppNotifications | { enabled?; showInContext?; position?; maxNotifications?; duration?; onClick?; customComponent? } | In-app toast notification behavior and custom rendering. |

Push

| Option | Type | Description | | --- | --- | --- | | pushNotifications.enabled | boolean | Enable browser push subscription flow. | | pushNotifications.vapidPublicKey | string | VAPID public key for push registration. | | pushNotifications.firebaseConfig | FBConfig | Firebase app config for push messaging. | | pushNotifications.serviceWorkerPath | string | Service worker path, default /firebase-messaging-sw.js. | | pushNotifications.serviceWorkerScope | string | Service worker scope, default /. | | pushNotifications.softAsk | boolean | Do not immediately trigger browser permission prompt. |

Custom Widgets and Overrides

You can replace key UI parts without forking the package.

| Override prop | Purpose | | --- | --- | | CustomMessageComponent | Fully custom message bubble/row rendering. | | CustomInputComponent | Custom composer and send controls. | | CustomScrollableArea | Custom scroll/list container (virtualized or custom behavior). | | CustomDaySeparator | Custom date separator component. | | CustomNewMessageLabel | Custom "new message" divider label. |

Example:

import { Chat } from '@ethora/chat-component';
import CustomMessageBubble from './CustomMessageBubble';
import CustomChatInput from './CustomChatInput';
import CustomScrollableArea from './CustomScrollableArea';
import CustomDaySeparator from './CustomDaySeparator';
import CustomNewMessageLabel from './CustomNewMessageLabel';

export default function App() {
  return (
    <Chat
      CustomMessageComponent={CustomMessageBubble}
      CustomInputComponent={CustomChatInput}
      CustomScrollableArea={CustomScrollableArea}
      CustomDaySeparator={CustomDaySeparator}
      CustomNewMessageLabel={CustomNewMessageLabel}
      config={{
        colors: { primary: '#1d4ed8', secondary: '#dbeafe' },
      }}
    />
  );
}

Reference example components in repository:

  • src/examples/customComponents/CustomMessageBubble.tsx
  • src/examples/customComponents/CustomChatInput.tsx
  • src/examples/customComponents/CustomScrollableArea.tsx
  • src/examples/customComponents/CustomDaySeparator.tsx
  • src/examples/customComponents/CustomNewMessageLabel.tsx

Push Notifications

Prerequisites

| Requirement | Why | | --- | --- | | HTTPS origin (or localhost) | Browser push APIs require secure contexts. | | Firebase project | FCM token + push transport setup. | | VAPID public key | Required for web push subscription. | | Service worker file | Required for background notification handling. |

Setup steps

  1. Copy service worker into your app's public assets:
npx @ethora/chat-component ethora-chat
  1. Configure push in config:
<Chat
  config={{
    pushNotifications: {
      enabled: true,
      vapidPublicKey: 'PLACEHOLDER_VAPID_PUBLIC_KEY',
      firebaseConfig: {
        apiKey: 'PLACEHOLDER_API_KEY',
        authDomain: 'PLACEHOLDER_AUTH_DOMAIN',
        projectId: 'PLACEHOLDER_PROJECT_ID',
        storageBucket: 'PLACEHOLDER_STORAGE_BUCKET',
        messagingSenderId: 'PLACEHOLDER_MESSAGING_SENDER_ID',
        appId: 'PLACEHOLDER_APP_ID',
      },
      serviceWorkerPath: '/firebase-messaging-sw.js',
      serviceWorkerScope: '/',
      softAsk: false,
    },
  }}
/>
  1. Optional: use hook directly for controlled permission flow:
import { usePushNotifications } from '@ethora/chat-component';

function PushPermissionButton() {
  const { requestPermission } = usePushNotifications({
    enabled: true,
    softAsk: true,
    vapidPublicKey: 'PLACEHOLDER_VAPID_PUBLIC_KEY',
  });

  return <button onClick={() => requestPermission()}>Enable Push</button>;
}

Auth Strategies

| Strategy | Config shape | Best for | | --- | --- | --- | | Default fallback (legacy quirk) | no auth block / defaultLogin | Legacy/demo flows; prefer explicit auth modes in production | | Injected user | userLogin: { enabled: true, user } | App already has authenticated user/session | | JWT login | jwtLogin: { enabled: true, token } | Token-based backend auth flow | | Google login | googleLogin: { enabled: true, firebaseConfig } | Google SSO using Firebase | | Custom login function | customLogin: { enabled: true, loginFunction } | Fully custom identity provider |

Example: injected user (bypass login screen)

<Chat
  config={{
    userLogin: {
      enabled: true,
      user: {
        _id: 'PLACEHOLDER_USER_ID',
        appId: 'PLACEHOLDER_APP_ID',
        walletAddress: 'PLACEHOLDER_WALLET_ADDRESS',
        defaultWallet: { walletAddress: 'PLACEHOLDER_WALLET_ADDRESS' },
        firstName: 'Jane',
        lastName: 'Doe',
        xmppPassword: 'PLACEHOLDER_XMPP_PASSWORD',
        token: 'PLACEHOLDER_ACCESS_TOKEN',
        refreshToken: 'PLACEHOLDER_REFRESH_TOKEN',
        username: 'PLACEHOLDER_USERNAME',
      },
    },
  }}
/>

Example: JWT login

<Chat
  config={{
    jwtLogin: {
      enabled: true,
      token: 'PLACEHOLDER_JWT_TOKEN',
    },
    refreshTokens: {
      enabled: true,
      refreshFunction: async () => {
        return {
          accessToken: 'PLACEHOLDER_NEW_ACCESS_TOKEN',
          refreshToken: 'PLACEHOLDER_NEW_REFRESH_TOKEN',
        };
      },
    },
  }}
/>

Hooks and API Exports

| Export | Type | Purpose | | --- | --- | --- | | Chat | React component | Main chat component. | | XmppProvider | React provider | Provides XMPP client context for internal hooks/state. | | useUnread | hook | Returns unread counters. | | logoutService | service | Programmatic logout utility. | | useQRCodeChat | hook | Handle QR-based room links. | | handleQRChatId | function | Parse/process QR chat ID from URL. | | useInAppNotifications | hook | Enables and handles in-app notifications. | | usePushNotifications | hook | Push subscription + foreground handling workflow. | | resendMessage | function | Retry sending failed/pending messages. |

Basic hook usage:

import { useUnread, logoutService } from '@ethora/chat-component';

function HeaderActions() {
  const { totalCount } = useUnread();

  return (
    <div>
      <span>Unread: {totalCount}</span>
      <button onClick={() => logoutService.performLogout()}>Logout</button>
    </div>
  );
}

logoutService.performLogout() behavior:

  • Dispatches chatSettingStore/logout
  • Dispatches rooms/setLogoutState
  • Dispatches roomHeap/clearHeap
  • Triggers logout middleware, which emits ethora-xmpp-logout
  • XmppProvider listens to that event and disconnects active XMPP client

Use Cases and Feature Coverage

| Area | Status in this package | | --- | --- | | One-room embedded chat | Available | | Multi-room chat UI | Available | | Message interactions (reply/copy/edit/delete/report/reactions) | Available | | Typing indicator | Available | | Profile interactions in chat | Available (can be disabled) | | File/media attachments | Available with ongoing enhancements | | In-app notifications | Available | | Web push notifications | Available | | Wallet/assets and extended social modules | Primarily in full Ethora platform |

Hosted vs Self-Host Guidance

| Model | Best for | Pros | Tradeoffs | | --- | --- | --- | --- | | Hosted Ethora backend | Fast time-to-market, smaller teams, MVPs | Fast setup, managed backend operations, easier push/auth onboarding | Less infrastructure-level control | | Self-hosted Ethora stack | Regulated environments, deep infra control | Full control over infrastructure, compliance customization, internal network deployment options | Higher DevOps/maintenance overhead | | Hybrid | Gradual migration or split workloads | Can start fast and migrate critical paths later | More architecture complexity |

Feature Roadmap

This is a practical planning snapshot for cross-platform consumers. It is not a release commitment.

| Surface | Current state | Notes | | --- | --- | --- | | Web React (@ethora/chat-component) | Available now | This repository. | | React Native | Via broader Ethora stack | Track platform-specific implementation in Ethora repos/docs. | | Swift (iOS native) | Planned / ecosystem-level | Confirm status with Ethora team for production timelines. | | Kotlin (Android native) | Planned / ecosystem-level | Confirm status with Ethora team for production timelines. | | Flutter | Planned / ecosystem-level | Confirm status with Ethora team for production timelines. | | Additional roadmap items | Ongoing | Media improvements, richer profile/wallet experiences, broader integration guides. |

Troubleshooting

| Issue | Likely cause | Fix | | --- | --- | --- | | useXmppClient must be used within an XmppProvider | Using internal XMPP-dependent logic without provider context | Wrap the app tree with XmppProvider where needed. | | Chat loads but no rooms appear | Auth/app context mismatch or room fetching restrictions | Verify appId, user credentials/tokens, baseUrl, and customRooms settings. | | Push permission never appears | softAsk: true without manual trigger, insecure origin, or missing VAPID key | Trigger requestPermission(), use HTTPS/localhost, set valid VAPID key. | | Service worker not found | firebase-messaging-sw.js missing in public dir | Run npx @ethora/chat-component ethora-chat or copy file manually. | | Login loop / auth failure | Wrong token/user object shape | Validate jwtLogin, userLogin.user, and refresh token flow. |

Ethora Links and Support

Product

  • Website: https://ethora.com/
  • Try Ethora: https://app.ethora.com/register

Developer Docs

  • Chat component docs: https://docs.ethora.com/
  • Ethora GitHub hub: https://github.com/dappros/ethora
  • This package repo: https://github.com/dappros/ethora-chat-component
  • Ethora GitHub organization: https://github.com/dappros
  • API docs (public): https://app.dappros.com/api-docs/
  • API docs (environment used in this repo): https://api.ethoradev.com/api-docs

Community and Support

  • Forum: https://forum.ethora.com/
  • Discord: https://discord.gg/Sm6bAHA3ZC
  • Contact: https://ethora.com/#contact

License

AGPL. See LICENSE.txt.