Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelogContact
Components
Buttons & Actions
ButtonButton GroupCopy ButtonDelete ButtonTheme ToggleToggleToggle Group
Inputs
Avatar UploadCalendarCheckboxColor PickerComboboxCountry SelectCron PickerCurrency InputDate PickerDate Range PickerDate Time PickerDuration PickerEmail InputEmoji PickerFile UploadFilter BuilderInputInput GroupListboxMasked InputMention InputMonth PickerMulti SelectNumber InputOTP InputPassword InputPhone InputRadio GroupRatingSearch InputSegmented ControlSelectSignature PadSliderSwitchTag InputTextareaTime PickerTimezone SelectTree Select
Forms
Address InputBooking WidgetCSV ImportFieldForm WizardInline EditInvoice line itemsRich Text EditorSchema Builder
Navigation
Back To TopBounce SidebarBreadcrumbCommand MenuGlobal SearchGooey NavHook SidebarNav MenuNav TabsPaginationProximity SidebarScroll ProgressSidebarStepsTable Of ContentsTabsTopbarUser MenuWorkspace Switcher
Overlays
Alert DialogContext MenuDialogDrawerDropdown MenuFamily DrawerHover CardPopoverShare DialogSheetShortcuts DialogTooltipTour
Feedback
AlertBannerCookie ConsentEmoji ReactionEmpty StateNotification BellNotification CenterProgressRoute ProgressSetup ChecklistSkeletonSpinnerToast
Data Display
Approval FlowAvatarBadgeCalendar ViewCode BlockComment ThreadContact cardCountdownDescription ListDiff ViewerFile ListFile managerFolderGanttJSON ViewerKbdLog ViewerMarkdownPresenceSchedulerTagTimelineTree View
Tables & Lists
Audit LogData TableDeal PipelineEditable GridKanbanListMembers tablePermissions MatrixTableTask ListVirtual List
Charts & Stats
Animated CounterArea chartBar chartDonut chartFunnel chartGaugeGitHub ActivityHeatmap calendarLeaderboardLine chartRadar chartRadial barSparklineStat CardTrackerTrend badge
Layout
AccordionApp ShellCardCollapsibleDetail LayoutEntity HeaderPage HeaderScroll AreaSeparatorSettings LayoutSplit ViewToolbar
Media
Audio PlayerCarouselCSV ViewerDOCX EditorDOCX ViewerExcel ViewerFile SystemImage compareImage CropperImage GalleryImage LightboxLocation MapPDF ViewerPowerPoint ViewerQR CodeStep PlayerVideo Player
AI Kit
Agent Status CardChat MessageChat ThreadChat WidgetConversation ListFluid OrbGrid RevealMatrix OrbModel PickerPrompt InputReasoning IndicatorRule BuilderSuggestion ChipsTool Call TimelineUsage MeterVoice InputWorkflow Canvas
Text & Effects
Background PatternGravity LettersMarqueeTerminalText AnimateText Rotate
Mobile
Action SheetBottom Tab BarFABHaptic ButtonHero HeaderInstall PromptLarge Title HeaderNotification BannerOnboarding CarouselPicker WheelPull To RefreshSlide To ConfirmSticky CTA BarSwipe DeckSwipeable Tabs
Commerce
Cart drawerCategory pickerCheckout stepsCoupon inputFavorite buttonFilter panelListing cardListing gridOrder trackerPricePrice rangePricing tableProduct galleryQuantity stepperReviewsSeller card
Marketing Sections
App Download SectionBlog Cards SectionCTA SectionFAQ SectionFeature GridFeature ShowcaseHero SectionIntegrations SectionLogo CloudMarketing FooterMarketing HeaderMarketing SectionNewsletter SectionPricing SectionStats SectionSteps SectionTeam SectionTestimonials SectionTimeline SectionVideo Section
Blocks
Admin Dashboard PageAdmin ShellAI Chat PageAPI Keys PageAutomation Builder PageCheckout PageCRM Contact PageCRM Pipeline PageError PagesInbox PageInvoice PageKPI DashboardListing Detail PageLogin PageMarketplace Home PageMarketplace Search PageMarketplace ShellMobile App HomeOnboarding FlowOrder History PagePost Listing WizardPricing PageProfile PageRegister PageSettings PageUsers Admin Page
Templates
About PageAcademy PageAccessibility PageAffiliate PageAgency PageAI Product PageAppointment Booking PageBlog PageBlog Post PageBug Bounty PageCareers PageChangelog PageCommunity PageCompare PageContact PageCustomer Story PageCustomers PageDemo Booking PageDevelopers PageDocs Home PageDownload PageEnterprise PageEvents PageExperts PageFAQ PageFeature PageGlossary PageHelp Article PageHelp Center PageHome Services PageImpact PageIntegration Detail PageIntegrations PageJob Detail PageLanding PageLaunch PageLegal PageManifesto PagePortfolio PagePress PageProduct Tour PagePromo PageReal Estate PageReferral PageResearch Report PageRestaurant PageRoadmap PageROI Calculator PageSecurity PageSolutions PageStartups PageStatus PageStorefront PageSwitch PageTemplate Gallery PageTravel PageWaitlist PageYear in Review Page
Hooks & Utilities
AI ChatChart kitCommerceDate utilsFile exportFile typesFiltersForm validationHapticsInvoicingMotion presetsNavigationNumber formatRelative timeRomanian locationsSpreadsheetText matchTonesUIProvideruseClipboarduseConsentuseControllableStateuseCooldownuseDebounceuseKeyboardInsetuseLocaleuseLongPressuseMediaControlsuseMediaQueryuseOverflowItemsusePersistedStateuseScrollEdgesuseScrollStateuseSelectionuseShortcutuseStickToBottom
GalleryTheme

AI Kit

Chat Widget

AI Kit

Chat Widget React block for Tailwind CSS v4

Chat ThreadConversation List
Live props
Content
greeting
intro
replyTime
botName
launcherLabel
Behavior
mode
allowAttachments
showRating
locale
Layout
position
strategy
offset20px
safeArea
State
defaultOpen
defaultTab
defaultConversationId
unread
Appearance
tone
color
header
size
radius
Code
import ChatWidget from "@/components/blocks/chat-widget"

<ChatWidget />
  1. Home
  2. Components
  3. AI Kit
  4. Chat Widget
Pro

Chat Widget React block for Tailwind CSS v4

v1.0.0·Added in 1.14.0

A React support chat widget like Intercom or Crisp: a floating launcher that opens Home, Messages and Help, with an AI agent and a handoff.

Press the round launcher (a real button; its badge counts unread replies) and the panel grows out of its corner on a spring while the icon turns into a chevron. Home greets the visitor with the team's avatars and presence dots, the typical reply time, the most recent conversation and a help search that filters articles as you type. Messages lists every conversation with unread counts; Help groups articles by collection and opens them in place. Arrow keys, Home and End move between the three tabs. Send us a message starts a conversation: the AI agent greets you with quick reply chips, searches the help center while a shimmering line says so, and links the article it used. Talk to a person (in the notice bar or a chip) hands the conversation to a teammate, who joins and types back. Enter sends, Shift+Enter adds a line, the paperclip attaches files. End the conversation and a star rating asks how it went. New replies are announced politely to screen readers. Escape closes the panel and puts focus back on the launcher. On a phone the panel fills the screen with safe-area padding and the composer rides above the keyboard.

Chat Widget is a Pro React block in the React AI components category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add chat-widget, together with Avatar, Button, Chat Message, Presence, Prompt Input and 11 more and the npm packages motion and lucide-react.

Add to a project

Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup

npx wingo-ui@latest add chat-widget

Chat Widget is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans

Usage

Import ChatWidget from @/components/blocks/chat-widget.

import { ChatWidget, type ChatWidgetSendHandler } from "@/components/blocks/chat-widget"

const answer: ChatWidgetSendHandler = async (input, { conversation, mode, signal }) => {
  const response = await fetch("/api/support", {
    method: "POST",
    body: JSON.stringify({ conversationId: conversation.id, mode, text: input.text }),
    signal,
  })
  const data: { reply: string } = await response.json()
  return { text: data.reply, quickReplies: [{ label: "Talk to a person", action: "handoff" }] }
}

export function SupportChat() {
  return (
    <ChatWidget
      greeting="Hi Emma"
      replyTime="under 5 minutes"
      color="#4f46e5"
      onSend={answer}
      onRate={(rating, conversation) => console.log(conversation.id, rating)}
    />
  )
}

Props

  • greetingdefault "Hi there"
    ReactNode

    The big line at the top of the Home tab. Put the visitor's name in it when you know it.

  • introdefault "How can we help today?"
    ReactNode

    The line under the greeting.

  • replyTimedefault "a few minutes"
    string

    How fast the team answers, read as "We typically reply in a few minutes" on Home, in human conversations and in the handoff note.

  • botNamedefault "Support AI"
    string

    The AI agent's name in its greeting, its header and the screen reader announcements.

  • launcherLabeldefault ""
    string

    A text label next to the launcher icon, like "Chat with us". Empty keeps the round launcher.

  • teamdefault "CHAT_WIDGET_TEAM"
    ChatWidgetAgent[]

    The people behind the chat: { id, name, avatar?, role?, status?: "online" | "away" | "busy" | "offline" }. They show as a presence stack on Home, and the first online person answers human conversations.

  • articlesdefault "CHAT_WIDGET_ARTICLES"
    ChatWidgetArticle[]

    Help articles: { id, title, description?, collection?, body?, href?, readTime?, keywords? }. Searched on Home and Help, grouped by collection, opened in the panel (or in a new tab with href), and quoted by the pretend AI agent.

  • conversations
    ChatWidgetConversation[]

    Controlled conversations: { id, mode?, agentId?, messages, unread?, status?: "open" | "resolved", rating? }. A message is { id, from: "user" | "agent" | "bot" | "system", text, agentId?, createdAt?, attachments?, quickReplies?, articleIds? }; agent and bot text is markdown.

  • defaultConversationsdefault "CHAT_WIDGET_CONVERSATIONS"
    ChatWidgetConversation[]

    The starting conversations while uncontrolled. Pass [] for a visitor who never wrote in.

  • onConversationsChange
    (conversations: ChatWidgetConversation[]) => void

    Every change: a sent message, a reply, a handoff, a read conversation, a rating. Save it to keep the history.

  • quickRepliesdefault "CHAT_WIDGET_QUICK_REPLIES"
    ChatWidgetQuickReply[]

    The chips under the AI agent's greeting in a new conversation. A string is sent as a message; { label, action: "handoff" | "resolve" } calls a person in or ends the conversation.

  • modedefault "ai"
    "ai" | "human"

    Who answers a new conversation. ai: the AI agent answers at once, with a Talk to a person notice and chip that hands over to the team. human: the team answers and the presence stack and reply time set expectations.

  • positiondefault "bottom-right"
    "bottom-right" | "bottom-left"

    The corner of the launcher; the panel grows out of it.

  • strategydefault "fixed"
    "fixed" | "absolute"

    fixed pins the widget to the viewport (the usual choice, render it once in your layout). absolute keeps it inside the nearest positioned container, for previews and app frames. The playground stage holds both.

  • offsetdefault 20
    number

    Distance in px from the screen edges, on top of the safe-area insets.

  • defaultOpendefault false
    boolean

    Opens the panel on mount without moving focus. Turn it on to see the Home tab.

  • open
    boolean

    Controlled open state of the panel.

  • onOpenChange
    (open: boolean) => void

    Runs when the launcher, the close button or Escape opens or closes the panel.

  • defaultTabdefault "home"
    "home" | "messages" | "help"

    The tab the panel starts on.

  • tab
    "home" | "messages" | "help"

    Controlled tab.

  • onTabChange
    (tab: ChatWidgetTab) => void

    Runs when a tab is picked, or when Back leaves a conversation for Messages.

  • conversationId
    string | null

    The open conversation, controlled; null shows the tabs. Open a thread from a "Contact support" button elsewhere in the app.

  • defaultConversationIddefault ""
    string | null

    The conversation open on mount while uncontrolled. The playground offers the two sample threads and opens the panel on them.

  • onConversationIdChange
    (id: string | null) => void

    Runs when a conversation opens or Back closes it.

  • tonedefault "neutral"
    "neutral" | "brand" | "success" | "warning" | "danger" | "info"

    The launcher, the Home header wash, the visitor's bubbles, the AI mark and the send button.

  • colordefault ""
    string

    Any CSS color, your brand color. Replaces the tone everywhere; text on the fill turns black or white by lightness.

  • headerdefault "soft"
    "soft" | "solid"

    The Home header: a soft wash of the color fading into the panel, or a solid fill like Intercom.

  • sizedefault "md"
    "sm" | "md" | "lg"

    The launcher: 48 / 56 / 64px with a 20 / 24 / 28px icon. The panel sits 12px above it.

  • radiusdefault "lg"
    "none" | "sm" | "md" | "lg"

    The panel's corners from 768px: 0 / 12 / 16 / 24px. On phones the panel fills the screen without corners.

  • allowAttachmentsdefault true
    boolean

    The composer's attach button, drop and paste. Files arrive in onSend as attachments and show in the visitor's bubble.

  • showRatingdefault true
    boolean

    Asks for a 1 to 5 star rating when a conversation ends (That helped, or the End conversation button).

  • safeAreadefault true
    boolean

    Keeps the launcher, the full-screen phone panel's header and its composer clear of the notch and the home indicator.

  • unreaddefault -1
    number

    The launcher badge, 0 hides it. -1 (the default) uses the sum of the conversations' unread counts; replies that arrive while the panel is closed add to it.

  • launcherIcon
    ReactNode

    Replaces the chat bubble icon of the closed launcher.

  • logo
    ReactNode

    Your logo at the top left of the Home tab. Defaults to the AI agent's mark.

  • botAvatar
    ReactNode

    Replaces the sparkle in the AI agent's round mark (an image, your logo).

  • onSenddefault "pretendChatWidgetReply"
    (input: { text, attachments }, context: { conversation, mode, articles, team, labels, signal }) => ChatWidgetReply | Promise<ChatWidgetReply | void>

    Answers a message. Return the reply (a string or { text, from?, agentId?, quickReplies?, articleIds? }) and the widget shows the typing state until it arrives; return nothing and push replies into conversations yourself. The default pretends: the AI agent quotes the best matching article, a teammate acknowledges.

  • onHandoff
    (conversation: ChatWidgetConversation) => ChatWidgetReply | Promise<ChatWidgetReply | void>

    Talk to a person: notify your team and return their first message. Default a pretend greeting from the first online teammate.

  • onRate
    (rating: number, conversation: ChatWidgetConversation) => void

    The satisfaction rating, 1 to 5, when the visitor sends it.

  • onArticleOpen
    (article: ChatWidgetArticle) => void

    Runs when an article opens, in the panel or in a new tab.

  • localedefault ""
    string

    The locale of the relative times (2 hr. ago). Empty uses the UIProvider's, then the browser's.

  • labels
    Partial<ChatWidgetLabels>

    Every string: tab names, the launcher and close names, the reply time sentence, the AI notice and Talk to a person, the handoff and joined notes, the rating copy and its five star labels, the pretend replies and the screen reader announcements.

  • classNames
    Partial<Record<"launcher" | "badge" | "panel" | "header" | "hero" | "card" | "tabs" | "tab" | "thread" | "chips" | "composer" | "rating" | "article", string>>

    Extra classes for the inner parts.

  • className
    string

    Extra classes for the root, the layer that holds the launcher and the panel.

Parts

  • pretendChatWidgetReply

    function

    The default onSend: waits a moment (aborts with the signal), then the AI agent answers from the best matching article with That helped and Talk to a person chips, or a teammate acknowledges in human mode. Wrap it to fall back on it.

  • searchChatWidgetArticles

    function

    searchChatWidgetArticles(query, articles): the articles whose title, description, collection or keywords hold every word, title matches first. The Home and Help search use it.

  • DEFAULT_CHAT_WIDGET_LABELS

    constant

    The English strings. Type: ChatWidgetLabels.

  • CHAT_WIDGET_TEAM

    constant

    The sample team: Olivia Bennett, Marcus Reed (online) and Priya Shah (away).

  • CHAT_WIDGET_ARTICLES

    constant

    Seven sample help articles in Account, Billing and Getting started.

  • CHAT_WIDGET_CONVERSATIONS

    constant

    Two sample conversations: an unread billing thread with Priya and a resolved, rated AI answer.

  • CHAT_WIDGET_QUICK_REPLIES

    constant

    The default chips under the AI agent's greeting.

  • ChatWidgetConversation

    type

    { id, mode?, agentId?, messages: ChatWidgetMessage[], unread?, status?, rating? }.

  • ChatWidgetMessage

    type

    { id, from: "user" | "agent" | "bot" | "system", text, agentId?, createdAt?, attachments?, quickReplies?, articleIds? }.

  • ChatWidgetReply

    type

    What onSend and onHandoff return: a string, or { text, from?: "bot" | "agent", agentId?, quickReplies?, articleIds? }.

  • ChatWidgetSendHandler

    type

    The type of onSend.

Examples

Open

Brand color, solid header

A custom color paints the launcher, the Home header, the visitor's bubbles and the send button.

Open

The team answers

mode="human": no AI agent, the presence stack and the reply time set expectations, a teammate types back.

Open

Closed, with an unread badge

Bottom left, a large launcher with a text label; the badge counts unread replies and pops in on a spring.

Open

Satisfaction rating

A resolved conversation ends with a star rating; onRate receives the score and the conversation.

Open

Controlled, with your backend

open and conversationId are controlled from buttons outside; onSend returns the reply and its quick replies.

Dependencies

motionlucide-reactavatarbuttonchat-messagepresenceprompt-inputratingreasoning-indicatorsearch-inputsuggestion-chipsuse-controllable-stateuse-keyboard-insetuse-media-querymotionrelative-timetonesui-config

Files

  • components/blocks/chat-widget.tsx
  • components/blocks/chat-widget-data.ts

FAQ

Is the React Chat Widget block free?

The preview, props and docs are free; copying the source needs a Pro plan. See plans.

How do I install Chat Widget?

Run npx wingo-ui@latest add chat-widget. It also adds the Wingo UI items it builds on (Avatar, Button, Chat Message, Presence, Prompt Input and 11 more) and the npm packages motion and lucide-react. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/chat-widget.

How does Chat Widget behave on phones?

On a phone the panel fills the screen with safe-area padding and the composer rides above the keyboard.

See also

Chat MessagePrompt InputSuggestion ChipsPresenceFAB

More React AI components

Conversation ListReasoning IndicatorRule BuilderTool Call TimelineUsage MeterFluid Orb
All 17 React AI components
PreviousChat ThreadNext Conversation List