Chat UI and theming

KletsoLauncher, KletsoChat, opening as a sheet or full screen, conversation list, KletsoTheme from your dashboard branding, dark mode.

Launcher

Scaffold(floatingActionButton: KletsoLauncher())

KletsoLauncher({client, presentation = sheet, icon, tooltip = 'Chat with us', onPressed}). Shows an unread dot when an assistant message completes while the chat is closed. Colours and size come from KletsoTheme (primary, onPrimary, launcherSize).

Opening the chat

await Kletso.instance.open(context);                                   // bottom sheet
await Kletso.instance.open(context, presentation: KletsoPresentation.fullscreen);
Kletso.instance.close();                                               // from anywhere
  • Sheet: a modal bottom sheet at 90% height on phones; on screens wider than 720 px it docks bottom-right at 420×640 with rounded corners.
  • Fullscreen: a MaterialPageRoute with fullscreenDialog: true.

open is a no-op while the chat is already open (client.ui.isOpen). close works for user taps and for server commands.

Embedding

const KletsoChat(showHeader: true, composerHint: 'Message…')

KletsoChat({client, theme, markdownRenderer, showHeader, onClose, emptyStateText, composerHint}) is the whole chat: header with agent name and status, connection banner, reverse message list with streaming bubbles, tool-call chips, rendered surfaces, typing dots, a “new messages” pill and the composer. Put it in a tab, a drawer or a page.

Other widgets: KletsoConversationList (the user’s conversations plus a “new conversation” row), KletsoSurfaceView(surface: …) (render one surface anywhere, for previews or a home-screen card), KletsoChatHeader, KletsoComposer, KletsoConnectionBanner, KletsoBotBubble, KletsoUserBubble, KletsoToolCallChip.

Markdown

Assistant text is rendered with KletsoPlainMarkdownRenderer (bold, italics, lists, links, inline code; zero dependencies so Wasm builds stay clean). Implement KletsoMarkdownRenderer to plug in your own renderer.

Theming

KletsoTheme is a ThemeExtension. Add it to your ThemeData and every Kletso widget picks it up:

final kletsoTheme = KletsoTheme.fromServer(Kletso.instance.session.value!.theme);
MaterialApp(
  theme: ThemeData(extensions: [kletsoTheme]),
  darkTheme: ThemeData(brightness: Brightness.dark, extensions: [KletsoTheme.dark()]),
)
FactoryUse
KletsoTheme.light() / .dark()Kletso defaults (Dutch Orange, Deep Navy, Cream; Plus Jakarta Sans bundled)
KletsoTheme.forBrightness(b)Pick by brightness
KletsoTheme.fromServer(json, base:)Apply the branding configured in Settings → Widget branding, delivered in the session bootstrap: primary, onPrimary, surface, background, text, textMuted, radius, fontFamily, launcher.position
KletsoTheme.of(context)Lookup; falls back to brightness defaults, never throws
useHostFont: trueInherit your app’s font instead of the bundled one

Fields you can copyWith: colours (primary, primaryHover, primarySoft, surface, background, text, textMuted, line, bubbleUser, bubbleBot, success, warning, error, info and their soft variants), radii (radiusSm, radiusMd, radiusLg, radiusPill), text styles (title, subtitle, body, caption, code), launcherPosition, launcherSize.

theme.materialTheme(hostTheme) returns a ThemeData tuned to the Kletso palette if you want the chat route to follow it fully.

Last updated 2026-09-28 · Report an issue with this page