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

@mypatientspace/chatbot-widget

v1.0.78

Published

Embeddable healthcare chatbot widget for websites and mobile apps

Readme

MPS Chatbot Widget

A standalone chatbot widget that third-party websites can embed via a single <script> tag.

npm version

Features

  • Self-contained React application bundled into a single JS file
  • Easy integration with any website
  • Embedded mode (default) or floating button mode
  • Customizable theming with light, dark, and system color modes
  • Style isolation (won't conflict with host site CSS)
  • Native mobile support via WebView
  • Voice input support
  • Quick action buttons
  • Survey/questionnaire support
  • Content citations with overlay view

Tech Stack

  • React 19 with TypeScript
  • Vite (library mode build)
  • Emotion (CSS-in-JS for style isolation)
  • lucide-react (icons)

Compatibility

Via CDN/Script Tag (Any Project)

When using the UMD bundle via <script> tag, the widget bundles its own React and renders in an isolated container. Your project's React version doesn't matter — this works with any framework (or no framework at all), including:

  • Vanilla JavaScript/HTML
  • jQuery
  • Angular, Vue, Svelte
  • Older React versions (14, 15, 16, etc.)

Via npm Import (React 18+ Required)

When importing as an ES module in a React project:

import '@mypatientspace/chatbot-widget';

You need React 18 or higher. The widget uses modern React features (hooks, Context API) that aren't available in older versions.

| Integration Method | React Version Required | |--------------------|------------------------| | CDN / Script tag | Any (bundles own React) | | npm import | React 18+ |

Installation

Via CDN (Recommended)

unpkg:

<script src="https://unpkg.com/@mypatientspace/chatbot-widget@latest/dist/mypatientspace-widget.umd.js"></script>

jsDelivr:

<script src="https://cdn.jsdelivr.net/npm/@mypatientspace/chatbot-widget@latest/dist/mypatientspace-widget.umd.js"></script>

Via npm

npm install @mypatientspace/chatbot-widget

Development

# Install dependencies
yarn install

# Start dev server (includes demo UI)
yarn dev

# Build for production
yarn build              # Builds both widget and demo
yarn build:widget       # Widget only
yarn build:demo         # Demo only

# Preview production build
yarn preview

Web Integration

Minimal Setup

<script src="https://unpkg.com/@mypatientspace/chatbot-widget@latest/dist/mypatientspace-widget.umd.js"></script>
<script>
  ChatbotWidget.init({
    apiEndpoint: 'https://your-api.com',
    token: 'your-auth-token'
  });
</script>

Full Customization

<script src="https://unpkg.com/@mypatientspace/chatbot-widget@latest/dist/mypatientspace-widget.umd.js"></script>
<script>
  ChatbotWidget.init({
    // API & Auth
    apiEndpoint: 'https://your-api.com',
    token: 'your-auth-token',
    userType: 'patient',             // 'patient' (default) or 'staff'
    assistantId: 'your-assistant-id',

    // Display mode
    floatingMode: true,          // false = embedded (default), true = FAB button
    position: 'bottom-left',     // FAB position (default: 'bottom-right')
    hideExpandButton: true,      // Hide expand/minimize button from header
    showCloseSlot: true,         // Empty placeholder for custom close button

    // Content
    headerTitle: 'Health Support',
    headerSubtitle: 'Online now',
    greeting: 'Hi! How can I help?',
    placeholder: 'Ask me anything...',
    brandingText: 'Powered by MyCompany',
    disclaimerText: 'AI can make mistakes. Verify important information.',
    headerIcon: '/logo.png',
    fabIcon: '/avatar.png',       // Only used in floating mode
    quickActions: ['I need help', 'Book appointment'],

    // Appearance
    colorMode: 'system',  // 'light', 'dark', or 'system' (auto-detect)
    theme: {
      colors: {
        primary: '#ff6600',        // FAB button, links, main accent
        primaryDark: '#cc5200',    // Hover states
        secondary: '#2d3748',      // Header background
        headerText: '#ffffff',     // Header text color
        background: '#ffffff',     // Chat window background
        surface: '#f7fafc',        // Input/card backgrounds
        text: '#2d3748',           // Primary text
        textLight: '#718096',      // Secondary text, timestamps
        userBubble: '#ff6600',     // User message background
        userBubbleText: '#ffffff', // User message text
        botBubble: '#edf2f7',      // Bot message background
        botBubbleText: '#2d3748',  // Bot message text
      },
      fontFamily: 'Inter, system-ui, sans-serif',
      borderRadius: '8px',
      shadow: '0 4px 12px rgba(0, 0, 0, 0.1)',
    },

    // Callbacks
    onOpen: () => console.log('Chat opened'),
    onClose: () => console.log('Chat closed'),
    onMessageSent: (message) => console.log('Sent:', message),
    onMessageReceived: (message) => console.log('Received:', message),
    onQuickAction: (action) => console.log('Quick action:', action),
    onStreamChunk: (chunk) => console.log('Chunk:', chunk),
    onCitationClick: (citation) => console.log('Citation:', citation),
    onNewChat: () => console.log('New chat started'),
    onWidgetReady: (api) => console.log('Widget ready:', api),
  });
</script>

Via npm import

import '@mypatientspace/chatbot-widget';

ChatbotWidget.init({
  apiEndpoint: 'https://your-api.com'
});

Patient & Staff Integration

The widget supports two user types with separate API routing. Each type uses different backend endpoints for chat, message history, and assistant lookup.

Patient (Default)

Patient mode is the default — no userType needed:

<script>
  ChatbotWidget.init({
    apiEndpoint: 'https://your-api.com',
    token: 'your-auth-token'
  });
</script>

API endpoints used:

  • POST /api/patient/chat/stream — Send messages
  • GET /api/patient/chat/messages — Load history
  • GET /api/patient/assistant — Get assistant config

Staff

Staff mode requires userType: 'staff' along with contextPatientId and patientTypeId:

<script>
  ChatbotWidget.init({
    apiEndpoint: 'https://your-api.com',
    token: 'your-auth-token',
    userType: 'staff',
    contextPatientId: 'patient-123',
    patientTypeId: 'type-456'
  });
</script>

API endpoints used:

  • POST /api/staff/chat/stream — Send messages (includes contextPatientId in body)
  • GET /api/staff/chat/messages — Load history (requires contextPatientId query param)
  • GET /api/staff/assistant/{patientTypeId} — Get assistant config

Required Fields by User Type

| Field | Patient | Staff | |-------|---------|-------| | apiEndpoint | Required | Required | | token | Required | Required | | userType | Optional (default) | 'staff' | | contextPatientId | Optional | Required | | patientTypeId | - | Required |

API Methods

ChatbotWidget.open();         // Open chat window
ChatbotWidget.close();        // Close chat window
ChatbotWidget.toggle();       // Toggle open/close
ChatbotWidget.startNewChat(); // Clear session and start new chat
ChatbotWidget.update(config); // Update widget configuration
ChatbotWidget.destroy();      // Remove widget completely

Embedded Mode

By default, the widget is embedded inside a container element. You can enable floating mode for a FAB button popup.

Using containerSelector

Embed the chat inside an existing element:

<div id="my-chat" style="width: 400px; height: 600px;"></div>

<script src="https://unpkg.com/@mypatientspace/chatbot-widget@latest/dist/mypatientspace-widget.umd.js"></script>
<script>
  ChatbotWidget.init({
    apiEndpoint: 'https://your-api.com',
    containerSelector: '#my-chat'
  });
</script>

Using floatingMode

Enable floating mode with FAB button (classic chatbot style):

<script>
  ChatbotWidget.init({
    apiEndpoint: 'https://your-api.com',
    floatingMode: true
  });
</script>

Comparison

| Feature | Embedded (default) | floatingMode: true | |---------|-------------------|----------------------| | FAB button | Hidden | Shown | | Chat visibility | Always open | Opens on click | | Position | Fills container | Fixed bottom-right/left | | Sizing | 100% of parent | 380x520px |

Mobile Integration

Android (Kotlin)

class ChatActivity : AppCompatActivity() {
    private lateinit var webView: WebView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        webView = WebView(this).apply {
            settings.javaScriptEnabled = true
            settings.domStorageEnabled = true
            loadDataWithBaseURL(
                "https://your-domain.com",
                """
                <!DOCTYPE html>
                <html>
                <head>
                    <meta name="viewport" content="width=device-width, initial-scale=1">
                </head>
                <body style="margin:0;padding:0;">
                    <script src="https://unpkg.com/@mypatientspace/chatbot-widget@latest/dist/mypatientspace-widget.umd.js"></script>
                    <script>
                        ChatbotWidget.init({
                            apiEndpoint: 'https://your-api.com'
                        });
                        ChatbotWidget.open();
                    </script>
                </body>
                </html>
                """.trimIndent(),
                "text/html", "UTF-8", null
            )
        }
        setContentView(webView)
    }
}

iOS (Swift)

import UIKit
import WebKit

class ChatViewController: UIViewController {
    var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let config = WKWebViewConfiguration()
        config.preferences.javaScriptEnabled = true

        webView = WKWebView(frame: view.bounds, configuration: config)
        webView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        view.addSubview(webView)

        let html = """
        <!DOCTYPE html>
        <html>
        <head>
            <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
            <style>body { margin: 0; padding: 0; }</style>
        </head>
        <body>
            <script src="https://unpkg.com/@mypatientspace/chatbot-widget@latest/dist/mypatientspace-widget.umd.js"></script>
            <script>
                ChatbotWidget.init({
                    apiEndpoint: 'https://your-api.com'
                });
                ChatbotWidget.open();
            </script>
        </body>
        </html>
        """

        webView.loadHTMLString(html, baseURL: URL(string: "https://your-domain.com"))
    }
}

iOS (Objective-C)

#import <UIKit/UIKit.h>
#import <WebKit/WebKit.h>

@interface ChatViewController : UIViewController
@property (nonatomic, strong) WKWebView *webView;
@end

@implementation ChatViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    WKWebViewConfiguration *config = [[WKWebViewConfiguration alloc] init];
    config.preferences.javaScriptEnabled = YES;

    self.webView = [[WKWebView alloc] initWithFrame:self.view.bounds configuration:config];
    self.webView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    [self.view addSubview:self.webView];

    NSString *html = @"<!DOCTYPE html>"
        "<html>"
        "<head>"
        "<meta name='viewport' content='width=device-width, initial-scale=1, maximum-scale=1'>"
        "<style>body { margin: 0; padding: 0; }</style>"
        "</head>"
        "<body>"
        "<script src='https://unpkg.com/@mypatientspace/chatbot-widget@latest/dist/mypatientspace-widget.umd.js'></script>"
        "<script>"
        "ChatbotWidget.init({ apiEndpoint: 'https://your-api.com' });"
        "ChatbotWidget.open();"
        "</script>"
        "</body>"
        "</html>";

    [self.webView loadHTMLString:html baseURL:[NSURL URLWithString:@"https://your-domain.com"]];
}

@end

React Native

import { WebView } from 'react-native-webview';

const ChatScreen = () => {
  const html = `
    <!DOCTYPE html>
    <html>
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1">
    </head>
    <body style="margin:0;padding:0;">
        <script src="https://unpkg.com/@mypatientspace/chatbot-widget@latest/dist/mypatientspace-widget.umd.js"></script>
        <script>
            ChatbotWidget.init({
                apiEndpoint: 'https://your-api.com'
            });
            ChatbotWidget.open();
        </script>
    </body>
    </html>
  `;

  return (
    <WebView
      source={{ html }}
      javaScriptEnabled={true}
      domStorageEnabled={true}
    />
  );
};

Configuration Reference

All Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | apiEndpoint | string | - | Base API URL, e.g. https://your-api.com (widget offline if not set) | | token | string | - | Auth token for API requests | | userType | 'patient' \| 'staff' | 'patient' | User type for API endpoint routing | | patientTypeId | string | - | Patient type ID for staff assistant lookup (required when userType is 'staff') | | sessionId | string | - | Existing session ID to resume | | assistantId | string | - | Specific assistant ID to use | | contextPatientId | string | - | Patient context for the chat | | loadHistory | boolean | true | Load previous chat history | | colorMode | 'light' \| 'dark' \| 'system' | 'light' | Color mode for the widget | | theme | ThemeConfig | - | Custom theme colors, fonts, border radius, shadow | | position | 'bottom-right' \| 'bottom-left' | 'bottom-right' | FAB button position | | containerSelector | string | - | CSS selector for embedded container | | floatingMode | boolean | false | Show FAB button and floating chat | | hideExpandButton | boolean | false | Hide the expand/minimize button from header | | showCloseSlot | boolean | false | Show empty circle placeholder for custom close button | | greeting | string | From API | Initial bot greeting message | | placeholder | string | From API | Input field placeholder text | | headerTitle | string | From API | Chat window header title | | headerSubtitle | string | From API | Chat window header subtitle | | headerIcon | string | From API | Header icon image URL | | fabIcon | string | From API | FAB button image URL | | brandingText | string | From API | Footer branding text | | disclaimerText | string | From API | Disclaimer text below input area | | quickActions | string[] | From API | Predefined quick action buttons |

Note: Content fields (greeting, headerTitle, placeholder, brandingText, headerIcon, fabIcon, quickActions, disclaimerText) are loaded from the assistant's API configuration by default. Setting them in the widget config overrides the API values.

Callbacks

| Callback | Parameters | Description | |----------|------------|-------------| | onOpen | () | Called when chat window opens | | onClose | () | Called when chat window closes | | onMessageSent | (message: Message) | Called after user sends a message | | onMessageReceived | (message: Message) | Called after bot response completes | | onQuickAction | (action: string) | Called when quick action is clicked | | onStreamChunk | (chunk: string) | Called for each streamed response chunk | | onCitationClick | (citation: Citation) | Called when a content card is clicked | | onNewChat | () | Called when user starts a new chat | | onWidgetReady | (api: WidgetApi) | Called when widget is ready with API methods |

Available Theme Colors

| Color | Light Default | Description | |-------|---------------|-------------| | primary | #00c2d1 | FAB button, links, main accent | | primaryDark | #017992 | Hover states | | secondary | #3c4d73 | Header background | | accent | #33b1e6 | Secondary accent color | | accentLight | #b8ebff | Light accent | | success | #00dec4 | Success states | | info | #30d7ed | Info states | | background | #ffffff | Chat window background | | surface | #fdfefe | Input/card backgrounds | | text | #3c4d73 | Primary text | | textLight | #6b7280 | Secondary text, timestamps | | userBubble | #00c2d1 | User message background | | userBubbleText | #ffffff | User message text | | botBubble | #e0f7fa | Bot message background | | botBubbleText | #3c4d73 | Bot message text | | border | #d1d5db | Border color | | borderLight | #e5e7eb | Light border | | error | #ef4444 | Error states | | errorBackground | #fef2f2 | Error background | | white | #ffffff | White color | | recording | #ef4444 | Voice recording indicator | | headerText | #ffffff | Header text and icon color | | scrollbarThumb | rgba(60, 77, 115, 0.2) | Scrollbar thumb color | | scrollbarThumbHover | rgba(60, 77, 115, 0.3) | Scrollbar thumb hover |

Default Fallback Values

Content fields are resolved with this priority: Config > Assistant API > Component default

| Field | Component Fallback | |-------|-------------------| | headerTitle | "AI Doctor" | | greeting | "Hello! Welcome to our healthcare support. How can I assist you today?" | | placeholder | "Type a message..." | | brandingText | "Developed by myPatientSpace" | | disclaimerText | "AI can make mistakes. Verify important information." | | headerIcon | MPS logo | | fabIcon | MPS logo | | quickActions | Empty (from API only) |

License

MIT