ChatLauncher

A floating chat button in a corner of the page that opens a chat panel. The panel is not modal: the page stays interactive, Escape closes it while focus is inside, and focus returns to the button. The chat stays mounted while the panel is closed (keepMounted, true by default), so the conversation and a running stream survive closing. Place it with position (bottom-right or bottom-left) and offset (24px, a number or { x, y }); size the panel with panelWidth (380) and panelHeight (640), both clamped to the viewport. When the panel does not fit, or the available width is below fullScreenBreakpoint (520px), it opens full screen and page scroll is frozen (mobileFullScreen). unreadCount shows a badge on the closed button. Open state can be controlled with opened / onOpenedChange or left to defaultOpened. It renders in a portal by default; set withinPortal={false} to keep it inside a container. To add the chat to a page that is not a React app, or to isolate it from the page CSS, use mountChatLauncher(target, element, options): it renders into a Shadow DOM with its own MantineProvider, injects the stylesheets you pass in styles or styleUrls, and returns unmount. See Embedding the launcher. The previews render the launcher with withinPortal={false} inside a page frame, so it measures the frame instead of the window.

Getting Started
$pnpm add @sinups/ai-kit @mantine/core @mantine/hooks @tabler/icons-react
Examples
Desktop and mobile
Full screen below 520px
Unread badge and keepMounted
API reference
Prop
Type
Required
children
React.ReactNode
Yes
Panel content, usually `AgentChat`
opened
boolean
No
Controlled open state
defaultOpened
boolean
No
Initial open state when `opened` is not controlled, `false` by default
onOpenedChange
(opened: boolean) => void
No
Called when the button, the close button or Escape changes the open state
position
ChatLauncherPosition
No
Corner of the viewport, `bottom-right` by default
offset
ChatLauncherOffset
No
Distance from the viewport edges in px, `24` by default; drops to 12px when the panel only fits that way
panelWidth
number
No
Panel width in px, never wider than the viewport, `380` by default
panelHeight
number
No
Panel height in px, never taller than the viewport, `640` by default
title
React.ReactNode
No
Panel header title
headerActions
React.ReactNode
No
Actions in the panel header before the close button
icon
React.ReactNode
No
Button icon while the panel is closed
unreadCount
number
No
Unread messages shown as a badge on the closed button, hidden at `0`
keepMounted
boolean
No
Keeps the panel content mounted while closed so the chat keeps its state, `true` by default
closeOnEscape
boolean
No
Closes the panel on Escape while focus is inside the launcher, `true` by default
mobileFullScreen
boolean
No
Opens the panel full screen when it does not fit or the available width is below `fullScreenBreakpoint`, `true` by default
fullScreenBreakpoint
number
No
Available width in px below which the panel opens full screen, `520` by default
withinPortal
boolean
No
Renders in a portal at the end of the document, `true` by default; turn off to position the launcher against a transformed container
zIndex
number
No
Stacking order of the button and the panel, `200` by default
labels
Partial<ChatLauncherLabels>
No
Overrides of the default English labels
className
string
No
Class name added to the root element
style
React.CSSProperties
No
Inline styles added to the root element
classNames
ChatLauncherClassNames
No
Class names of inner elements