A compact library of UI chat widgets and helpers for server and client integrations.
This repository ships three distributable packages:
- NuGet:
BbQ.ChatWidgets(the .NET library: services, renderers, endpoints) - npm:
@bbq-chat/widgets(the JavaScript/TypeScript client library: widgets, client helpers) - npm:
@bbq-chat/widgets-angular(Angular-native components and services)
Note: the .NET package no longer bundles the JavaScript client or theme CSS. Install the npm package (or bring your own UI) to render widgets in a browser.
Get a working button widget in under 30 seconds!
using Microsoft.Extensions.AI;
using BbQ.ChatWidgets.Extensions;
var builder = WebApplication.CreateBuilder(args);
// 1. Create chat client with function invocation
var apiKey = builder.Configuration["OpenAI:ApiKey"]
?? throw new InvalidOperationException("OpenAI:ApiKey not configured");
IChatClient chatClient = new ChatClientBuilder(
new OpenAI.Chat.ChatClient("gpt-4o-mini", apiKey).AsIChatClient())
.UseFunctionInvocation()
.Build();
// 2. Register BbQ services
builder.Services.AddBbQChatWidgets(options =>
{
options.ChatClientFactory = _ => chatClient;
options.EnablePersona = true; // opt-in: enable request/thread/default persona behavior
options.DefaultPersona = "You are a concise assistant."; // optional
});
var app = builder.Build();
// 3. Map endpoints
app.MapBbQChatEndpoints();
app.Run();import { WidgetManager } from '@bbq-chat/widgets';
// 1. Send a message
const response = await fetch('/api/chat/message', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: 'Show me a button', threadId: 'demo-123' })
});
const turn = await response.json();
// 2. Render widgets
const manager = new WidgetManager();
const container = document.getElementById('chat-container');
if (container && turn.widgets?.length) {
manager.renderInto(container, turn.widgets);
}import { Component, signal } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { WidgetRendererComponent } from '@bbq-chat/widgets-angular';
import type { ChatWidget } from '@bbq-chat/widgets-angular';
@Component({
selector: 'app-chat',
standalone: true,
imports: [WidgetRendererComponent],
template: `
<bbq-widget-renderer
[widgets]="widgets()"
(widgetAction)="handleWidgetAction($event)">
</bbq-widget-renderer>
`
})
export class ChatComponent {
widgets = signal<ChatWidget[]>([]);
constructor(private http: HttpClient) {}
sendMessage(text: string) {
this.http.post<{ widgets?: ChatWidget[] }>('/api/chat/message', { message: text, threadId: 'demo-123' })
.subscribe(turn => this.widgets.set(turn.widgets ?? []));
}
handleWidgetAction(event: { actionName: string; payload: any }) {
console.log('Action:', event.actionName, event.payload);
}
}π Full Getting Started Guide β | Widget Gallery β | Integration Paths β
- Interactive Chat Widgets: Buttons, forms, cards, dropdowns, sliders, toggles, file uploads, and more
- Server-Driven UI: The LLM decides which widgets to show based on conversation context
- Automatic Chat History Summarization: Efficiently manages long conversations by summarizing older turns
- SSE Support: Real-time server-pushed widget updates
- Triage Agents: Route conversations to specialized agents based on classification
- Type-Safe Widget Actions: Strongly-typed handlers for widget interactions
- Extensible Architecture: Swap out components via dependency injection
dotnet add [YOUR_PROJECT] package BbQ.ChatWidgetsnpm install @bbq-chat/widgetsnpm install @bbq-chat/widgets-angular @bbq-chat/widgetsUse component overrides to replace built-in widget components without writing switch/if logic.
<WidgetRenderer Widget="widget" OnAction="HandleWidgetAction">
<Overrides>
<WidgetOverride Type="typeof(InputWidget)" Template="typeof(MyCustomInputComponent)" />
<WidgetOverride TypeId="clock" Template="typeof(MyClockWidgetComponent)" />
</Overrides>
</WidgetRenderer>services.AddBbQChatWidgetsBlazor(overrides =>
{
overrides.Add<InputWidget, MyCustomInputComponent>();
overrides.Add(typeof(MyClockWidgetComponent), widgetTypeId: "clock");
});Resolution order is: local exact type -> local type id -> local assignable type -> global exact type -> global type id -> global assignable type -> built-in fallback.
- Getting Started - Complete setup guide
- Widget Gallery - Visual showcase of all widgets
- Integration Paths - Choose the right approach for your stack
- Use Cases & Tutorials - Step-by-step scenarios
- API Reference - Generated API docs
- Contributing Guide - How to contribute
./docs/generate-docs.ps1- .NET:
dotnet test - JS/TS:
npm test(run fromSample/WebApp/ClientApp)
See CHANGELOG.md for version history and release notes.
See LICENSE.