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

embeddable-ai-chat

v0.2.5

Published

Stencil Component Starter

Readme

embeddable-ai-chat

A framework-agnostic Web Component that renders a streaming AI chat widget and connects to an Embeddable orchestrator backend over a STOMP WebSocket.

Built with Stencil — works in plain HTML, React, Vue, Angular, or any other framework.


Quick start

Add this script to load the component latest version from unpkg (no build step required):

<script type="module" src="https://unpkg.com/[email protected]/dist/embeddable-ai-chat/embeddable-ai-chat.esm.js"></script>

Then add the component to your page. Choose between modal (floating panel) or inline (fills its container):

  1. Modal mode - the chat opens in a floating panel when the trigger is clicked
<em-ai-chat
  mode="modal"
  placement="bottom-right"
  orchestrator-url="wss://api.[us|eu].embeddable.com/ws"
  embeddable-tokens='["your-security-token"]'
  input-placeholder="Ask anything..."
>
  <button slot="trigger">Open chat</button> >
</em-ai-chat>
  1. Inline mode - the chat fills its container
<div style="width: 420px; height: 600px;">
  <em-ai-chat
    mode="inline"
    orchestrator-url="wss://api.[us|eu].embeddable.com/ws"
    embeddable-tokens='["your-security-token"]'
    input-placeholder="Ask anything..."
  ></em-ai-chat>
</div>

See demo.html for a full working example.


Props

| Attribute | Type | Default | Description | | ------------------- | -------------------------------------------------------------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | orchestrator-url | string | — | WebSocket URL of the Embeddable orchestrator backend (ws:// or wss://) | | embeddable-tokens | string | — | JSON-encoded array of security tokens. The first token is used as the Bearer credential. | | mode | "modal" \| "inline" | "inline" | modal opens a floating draggable panel; inline fills its container | | placement | "bottom-right" \| "bottom-left" \| "top-right" \| "top-left" | "top-right" | Where the modal panel appears relative to the trigger element | | welcome-message | string | — | Message shown in the empty state before the user sends their first message | | input-placeholder | string | — | Placeholder text inside the message input | | supports-preview | "true" \| "false" | "true" | Tells the orchestrator whether this client can render Embeddable component previews. Sent as the Embeddable-Component-Preview-Supported header on the STOMP CONNECT frame. | | feedback-comment-title | string | "Tell us more" | Title of the feedback comment dialog | | feedback-comment-placeholder | string | "Share more (optional)" | Placeholder text inside the feedback comment input | | feedback-dismiss-label | string | "Dismiss" | Label for the dismiss button in the feedback dialog | | feedback-submit-label | string | "Submit rating" | Label for the submit button in the feedback dialog | | feedback-thanks-label | string | "Thanks for your feedback" | Confirmation message shown after feedback is submitted |

Slots

| Name | Description | | --------- | ----------------------------------------------------------------------- | | trigger | (modal mode only) The element that toggles the chat panel open/closed |


Theming

The component's visual properties are defined as --em-ai-chat-* CSS custom properties. By default, these resolve to tokens from the remarkable-ui design system — the --em-sem-* (semantic) and --em-core-* (primitive) token layers. You can see the full mapping in src/em-ai-chat/em-ai-chat.css.

If an <em-mbeddable> is already present in your app, the tokens --em-sem-* (semantic) and --em-core-* (primitive) will be automatically injected into the :root, and the style will be applied automatically.

If no <em-mbeddable> is present, or if you need specific styles for the chat, set the --em-ai-chat-* variables directly on :root (or on the element itself) to match your own design:

:root {
  /* Shell */
  --em-ai-chat-shell-background: #ffffff;
  --em-ai-chat-shell-border-color: #e4e4ea;

  /* Input composer */
  --em-ai-chat-composer-input-border-color: #e4e4ea;
  --em-ai-chat-composer-input-border-color--focus: #2d52cc;

  /* Primary icon button (send / cancel) */
  --em-ai-chat-icon-button-primary-background: #2d52cc;
  --em-ai-chat-icon-button-primary-color: #ffffff;

  /* Panel size (modal mode) */
  --em-ai-chat-width: 23.75rem;
  --em-ai-chat-height: 32.5rem;
}

The full list of available variables is in src/em-ai-chat/em-ai-chat.css.


Framework integration

React / Vue / Angular (ESM import)

import { defineCustomElements } from 'embeddable-ai-chat/loader';
defineCustomElements();

Then use <em-ai-chat> like any other HTML element:

return (
  <em-ai-chat embeddable-tokens={JSON.stringify([token])} orchestrator-url="wss://..." mode="modal">
    <button slot="trigger">Chat</button>
  </em-ai-chat>
);

Vite users — add this to vite.config.ts to prevent Vite from pre-bundling the loader (which breaks Stencil's lazy chunk resolution):

export default defineConfig({
  optimizeDeps: {
    exclude: ['embeddable-ai-chat'],
  },
});

Local development

npm install
npm start        # dev server with hot reload at http://localhost:3333

Edit src/index.html to change props or tokens while developing locally. The orchestrator backend is expected at ws://localhost:8080/ws by default.

npm run build    # production build → dist/

Architecture

em-ai-chat is the root component. It owns the STOMP WebSocket connection, holds all message state, and coordinates the child components below.

em-ai-chat
│   Root. Manages the STOMP WebSocket lifecycle, accumulates streaming
│   events into a display list, and switches between modal and inline modes.
│
├── em-ai-chat-modal-shell   (modal mode only)
│   Floating panel with trigger-based open/close, drag-to-reposition,
│   and mouse/keyboard resize. Persists panel size and position across toggles.
│
├── em-ai-chat-messages
│   Scrolling feed of user messages, assistant responses, tool calls, errors,
│   and injected components. Groups tool calls under their parent message
│   and auto-scrolls to the latest entry.
│
│   ├── em-ai-chat-message-feedback
│   │   Thumbs up/down rating attached to each assistant message.
│   │
│   └── em-ai-chat-component
│       Sandboxed host for Embeddable component bundles injected by the AI.
│       Injects theme tokens, scales height via ResizeObserver, and proxies
│       data-fetch requests to the orchestrator.
│
└── em-ai-chat-input
    Textarea composer. Enter sends, Shift+Enter adds a newline. Auto-focuses
    on visibility and toggles the action button between send and cancel
    while a response is streaming.

Incoming server events are processed by reduceEvent() in src/utils/messages.utils.ts. It maintains a Map<id, message> for O(1) streaming updates and returns a new array reference on each change to trigger Stencil re-renders.