Skip to content

deftio/quikchat

Repository files navigation

License NPM version CI

QuikChat

A lightweight, zero-dependency vanilla JavaScript chat widget. Drop it into any page — no React, no Vue, no build step required — and connect it to any LLM, WebSocket, or message source with plain fetch().

<script src="https://unpkg.com/quikchat"></script>
<link rel="stylesheet" href="https://unpkg.com/quikchat/dist/quikchat.css" />
const chat = new quikchat('#chat', async (chat, msg) => {
    chat.messageAddNew(msg, 'me', 'right', 'user');

    // Stream a response from any LLM
    const id = chat.messageAddTypingIndicator('bot');
    const response = await fetch('http://localhost:11434/api/chat', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            model: 'llama3.1',
            messages: chat.historyGet(),   // full conversation context
            stream: true
        })
    });

    const reader = response.body.getReader();
    let first = true;
    while (true) {
        const { value, done } = await reader.read();
        if (done) break;
        const token = JSON.parse(new TextDecoder().decode(value).trim()).message.content;
        if (first) { chat.messageReplaceContent(id, token); first = false; }
        else       { chat.messageAppendContent(id, token); }
    }
});

That's a working streaming LLM chat in one file — no bundler, no framework, no SDK.

Features

  • LLM-readyhistoryGet() returns { role, content } objects compatible with OpenAI, Ollama, Mistral, and Claude APIs
  • Streaming built inmessageAddNew()messageAppendContent() for token-by-token display
  • Typing indicator — animated "..." dots that auto-clear when streaming begins
  • Markdown support — three tiers: base (no markdown), -md (basic markdown via quikdown), -md-full (syntax highlighting, math, diagrams, maps — loaded on demand from CDN)
  • HTML sanitization — built-in XSS protection or plug in your own sanitizer
  • Themeable — 11 built-in CSS themes (light, dark, blue, warm, midnight, ocean, modern, glass, gradient, minimal, debug) or write your own
  • Multi-user — multiple users per chat, multiple independent chats per page
  • Message visibility & tagging — hide system prompts and tool-call results from the UI while keeping them in history for LLM context
  • History export / import — save and restore complete chat sessions (historyExport() / historyImport())
  • RTL supportsetDirection('rtl') for Arabic, Hebrew, and other right-to-left languages
  • Event callbacks — hooks for message add, append, replace, and delete events
  • Timestamps — optional per-message timestamps (show/hide)
  • Zero runtime dependencies — ~5 KB gzipped (base), ~9 KB with markdown, ~14 KB full
  • Any environment — works with CDN, npm, or local files; UMD, ESM, and CJS builds included
  • Responsive — fills its parent container and resizes automatically
  • Accessible — ARIA roles and labels on all interactive elements

Quick Start

CDN

<script src="https://unpkg.com/quikchat"></script>
<link rel="stylesheet" href="https://unpkg.com/quikchat/dist/quikchat.css" />

npm

npm install quikchat
import quikchat from 'quikchat';

With Markdown

<!-- Basic markdown (bold, italic, code, tables, lists) — ~9 KB gzip -->
<script src="https://unpkg.com/quikchat/dist/quikchat-md.umd.min.js"></script>

<!-- Full markdown (+ syntax highlighting, math, diagrams, maps) — ~14 KB gzip -->
<script src="https://unpkg.com/quikchat/dist/quikchat-md-full.umd.min.js"></script>

<link rel="stylesheet" href="https://unpkg.com/quikchat/dist/quikchat.css" />

The -md-full build uses quikdown's editor as a rendering engine. When your LLM returns a fenced code block with a language tag, highlight.js loads from CDN automatically. Same for math (MathJax), diagrams (Mermaid), and maps (Leaflet) — each loads on demand the first time it's encountered.

Same API across all three builds — just pick your script tag.

Usage

const chat = new quikchat(
    '#chat-container',           // CSS selector or DOM element
    (chat, msg) => {             // onSend callback
        chat.messageAddNew(msg, 'me', 'right');
    },
    {
        theme: 'quikchat-theme-light',
        titleArea: { title: 'My Chat', align: 'left', show: true },
    }
);

// Add messages programmatically
chat.messageAddNew('Hello!', 'Alice', 'left', 'user');
chat.messageAddNew('Hi there!', 'Bot', 'left', 'assistant');
chat.messageAddNew('System notice', 'system', 'center', 'system');

// Streaming pattern
const id = chat.messageAddTypingIndicator('bot');     // show "..." dots
chat.messageReplaceContent(id, firstToken);            // first token clears dots
chat.messageAppendContent(id, nextToken);              // append subsequent tokens

// Disable input while bot is responding
chat.inputAreaSetEnabled(false);
chat.inputAreaSetButtonText('Thinking...');
// ... after response completes ...
chat.inputAreaSetEnabled(true);
chat.inputAreaSetButtonText('Send');

// History is LLM-API compatible
const history = chat.historyGet();  // [{ role: "user", content: "..." }, ...]

Message Formatter & Sanitization

Process message content before display — render markdown, sanitize HTML, or both:

const chat = new quikchat('#chat', onSend, {
    // Sanitize user input (true = escape HTML entities, or pass a function)
    sanitize: true,

    // Format content (e.g., markdown → HTML)
    messageFormatter: (content) => myMarkdownParser(content),
});

// Change at runtime
chat.setMessageFormatter((content) => marked.parse(content));
chat.setSanitize((content) => DOMPurify.sanitize(content));

The pipeline is: sanitize → format → display. Sanitize cleans untrusted input; the formatter's output is trusted.

The -md and -md-full builds pre-wire quikdown as the formatter — no configuration needed. The -md-full build additionally renders syntax-highlighted code, math equations, Mermaid diagrams, and maps via dynamic CDN loading.

Theming

Themes are pure CSS — colors, borders, and shadows only. The base CSS handles all layout.

// Built-in themes
chat.changeTheme('quikchat-theme-light');
chat.changeTheme('quikchat-theme-dark');
chat.changeTheme('quikchat-theme-modern');   // chat-bubble style

// Or write your own — just color overrides
.my-theme {
    background-color: #f9f9f9;
    border: 1px solid #ccc;
    border-radius: 10px;
}
.my-theme .quikchat-title-area { color: #333; }
.my-theme .quikchat-messages-area { background-color: #fff; color: #333; }
.my-theme .quikchat-input-send-btn { background-color: #4caf50; color: white; border: none; border-radius: 4px; }

The modern bubble theme uses alignment classes (quikchat-align-left, quikchat-align-right) to position messages as chat bubbles with colored backgrounds — left-aligned messages appear as grey bubbles, right-aligned as blue.

Style messages by role with CSS hooks: .quikchat-role-user, .quikchat-role-assistant, .quikchat-role-system, .quikchat-role-tool.

Documentation

Guide Description
Getting Started Installation, minimal example, constructor options
API Reference Every public method, property, and return value
Streaming Token-by-token LLM response display
Multi-User Chat Multiple users, dual instances, message routing
LLM Integration Ollama, OpenAI, LM Studio, tool calls, conversational memory
Theming Custom themes, CSS architecture, built-in themes
CSS Architecture Base vs theme separation, ARIA accessibility

Demo & Examples

Live Demo | Examples

Examples include: basic UMD/ESM usage, theme switching, dual chatrooms, markdown rendering (basic and full with syntax highlighting + math + diagrams), streaming with Ollama/OpenAI/LM Studio, and React integration.

Build Variants

Build What you get Network
Base (quikchat.umd.min.js) Chat widget, zero deps None
Markdown (quikchat-md.umd.min.js) + bold, italic, code, tables, lists None
Full (quikchat-md-full.umd.min.js) + syntax highlighting, math, diagrams, maps CDN on demand
CSS (quikchat.css) All 11 themes None

All builds are also available in ESM and CJS formats with sourcemaps. See the downloads page for exact sizes, SRI hashes, and CDN links.

The -md builds bundle quikdown. The -md-full build post-processes fence blocks with dynamically loaded renderers (highlight.js, MathJax, Mermaid, Leaflet). The base builds have zero runtime dependencies.

Building from Source

npm install
npm run build    # lint, build all formats, report bundle sizes
npm test         # jest unit tests with coverage

Build-time tooling (rollup, babel, eslint, jest) is all in devDependencies — zero runtime dependencies.

Testing

npm test                # unit tests (jest, 100% coverage)
npm run test:e2e        # browser tests (playwright)

Development

npm run feature my-feature-name        # creates feature/my-feature-name, bumps patch
npm run feature my-feature-name minor  # bumps minor

A pre-commit hook runs lint and tests automatically before each commit.

See RELEASE-PROCEDURE.md for the full release workflow.

License

BSD-2-Clause

Home Page

github.com/deftio/quikchat