@ticket0-ai/widget
v1.1.4
Published
Embeddable chat widget for Ticket0 — drop-in chat widget + React component
Readme
@ticket0-ai/widget
Embeddable chat widget for Ticket0 — available as a React component package and a drop-in script tag.
Installation
npm install @ticket0-ai/widget
# or
pnpm add @ticket0-ai/widgetPeer dependencies: react >= 18, react-dom >= 18
Quick start
Drop-in (zero config)
Fetches your workspace theme, color, welcome message, and agent name from the Ticket0 app automatically.
import { Ticket0Chat } from "@ticket0-ai/widget"
export default function App() {
return (
<>
<YourApp />
<Ticket0Chat workspaceId="ws_abc123" />
</>
)
}Script tag (no bundler required)
<script
src="https://widget.ticket0.ai/v1/widget.js"
data-workspace="your-workspace-slug"
></script>Props
All props are optional except workspaceId. Server config is fetched from your workspace and merged with any props you provide (configMode: "merge" is the default).
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| workspaceId | string | required | Your workspace slug or ID |
| apiUrl | string | https://app.ticket0.ai | Base URL of the Ticket0 app |
| configMode | "merge" \| "server" \| "local" | "merge" | Config source strategy (see below) |
| theme | "light" \| "dark" \| "system" | "system" | Color theme |
| primaryColor | string | server value | Primary/accent hex color |
| backgroundColor | string | auto | Chat window background color |
| fontFamily | string | system font | Font family override |
| position | "bottom-right" \| "bottom-left" | server value | Widget position |
| welcomeMessage | string | server value | Greeting shown before first message |
| agentName | string | server value | Agent display name in header |
| agentAvatar | string | server value | Agent avatar URL |
| headerTitle | string | server value | Chat window title |
| inputPlaceholder | string | "Type a message…" | Textarea placeholder |
| locale | string | browser default | Locale for timestamps (e.g. "da") |
| zIndex | number | 2147483647 | CSS z-index |
| containerRef | RefObject<HTMLElement> | document.body | Portal target |
| defaultOpen | boolean | false | Start the widget open |
| hideOnMobile | boolean | false | Hide on screens ≤ 640px |
| soundEnabled | boolean | false | Play sound on new messages |
| onOpen | () => void | — | Called when the widget opens |
| onClose | () => void | — | Called when the widget closes |
| onMessageSent | (msg) => void | — | Called after a message is sent |
| onMessageReceived | (msg) => void | — | Called when an AI reply arrives |
Config modes
| Mode | Behaviour |
|------|-----------|
| "merge" (default) | Fetch server config, then apply any provided props as overrides |
| "server" | Use workspace server config only — props are ignored |
| "local" | Use props only — skip the server config fetch entirely |
Full custom example
<Ticket0Chat
workspaceId="ws_abc123"
theme="dark"
position="bottom-left"
primaryColor="#6366f1"
agentName="Support"
agentAvatar="/support-avatar.png"
welcomeMessage="How can we help you today?"
locale="da"
zIndex={9999}
onOpen={() => analytics.track("chat_opened")}
onMessageSent={(msg) => console.log("sent:", msg.bodyText)}
/>Headless / composable mode
For full UI control, use Ticket0Provider and the individual primitives.
Component composition
import {
Ticket0Provider,
Ticket0Launcher,
Ticket0ChatWindow,
Ticket0Trigger,
} from "@ticket0-ai/widget"
function MyApp() {
return (
<Ticket0Provider workspaceId="ws_abc123" theme="dark">
{/* Floating launcher button (portals to body) */}
<Ticket0Launcher />
{/* Floating chat window (portals to body) */}
<Ticket0ChatWindow />
{/* Custom trigger anywhere in the page */}
<Ticket0Trigger>
<button className="my-chat-button">Talk to us</button>
</Ticket0Trigger>
</Ticket0Provider>
)
}Fully custom UI with hooks
import { Ticket0Provider, useTicket0 } from "@ticket0-ai/widget"
function CustomChatButton() {
const { open, isOpen, unreadCount } = useTicket0()
return (
<button onClick={open} className="relative">
Chat with us
{unreadCount > 0 && (
<span className="badge">{unreadCount}</span>
)}
</button>
)
}
function App() {
return (
<Ticket0Provider workspaceId="ws_abc123" configMode="local" primaryColor="#000">
<CustomChatButton />
</Ticket0Provider>
)
}Hooks
useTicket0()
Returns the full chat state and controls.
const {
isOpen, // boolean
messages, // WidgetMessage[]
unreadCount, // number
isSending, // boolean
error, // string | null
open, // () => void
close, // () => void
toggle, // () => void
sendMessage, // (text: string) => Promise<void>
} = useTicket0()useTicket0Unread()
Returns just the unread count (optimised for badge displays).
const count = useTicket0Unread() // numberuseTicket0Config()
Returns the resolved config (server + overrides merged). Returns null while loading.
const config = useTicket0Config()
// config.primaryColor, config.agentName, config.theme, etc.Ticket0Trigger
An unstyled <button> that opens, closes, or toggles the widget on click.
Style it however you like.
<Ticket0Trigger action="open">
<span>💬 Chat</span>
</Ticket0Trigger>
<Ticket0Trigger action="close" className="my-close-btn">
Close chat
</Ticket0Trigger>| Prop | Type | Default |
|------|------|---------|
| children | ReactNode | required |
| action | "toggle" \| "open" \| "close" | "toggle" |
| className | string | — |
| style | CSSProperties | — |
TypeScript
Full type exports are included:
import type {
Ticket0ChatProps,
Ticket0ProviderProps,
Ticket0LauncherProps,
Ticket0ChatWindowProps,
Ticket0TriggerProps,
WidgetMessage,
ResolvedConfig,
Ticket0ChatState,
Theme,
Position,
ConfigMode,
} from "@ticket0-ai/widget"Features
- Server config by default — workspace theme, color, and copy fetched automatically
- Full prop override — every server value can be overridden
- Headless mode — use hooks and primitives to build your own UI
- TypeScript-first — complete type exports, zero
any - Dark mode —
theme="system"follows OS preference automatically - Accessible — keyboard navigation, focus trapping,
aria-*attributes, screen reader live regions - Typing indicator — animated dots while AI is composing a reply
- Feedback — 👍/👎 rating buttons on AI replies
- Email capture — optional email form to follow up on conversations
- Unread badge — shows message count while the widget is closed
- Escape to close — standard dialog keyboard behaviour
- Zero extra dependencies — only
reactandreact-domas peers
