Skip to content
WebMCP Agents
Esc
↑↓navigate↵open⌘Jpreview
On this page

Style the cursor and the chat

Give the agent your brand: one custom property recolours the cursor, its rings and the chat's accent, and a few more set the chat's surfaces, corners and typeface, in light and dark.

The cursor and the chat ship with a neutral black look. Both are styled with CSS custom properties: you set a few values in a stylesheet of your own and never touch their markup. The chat’s accent follows the cursor’s colour, so one property, --agent, brands both.

A complete example

One file holds the whole theme. The same file works in every framework.

/* One colour for the agent: the arrow, the tag, the rings and the
   chat's accent all follow --agent. `html` in front of a selector
   makes the rule win wherever this file is imported. */
html:root {
  --agent: #4f46e5;
  --agent-ink: #ffffff;
}

/* The chat: its own corners and typeface. */
html .wa-chat {
  --wa-chat-radius: 10px;
  --wa-chat-font: "Inter", system-ui, sans-serif;
}

Import it in your entry file, with the two stylesheets you already have:

import "@webmcp-agents/core/cursor.css";
import "@webmcp-agents/chat/chat.css";
import "./agent.css"; 
/* One colour for the agent: the arrow, the tag, the rings and the
   chat's accent all follow --agent. `html` in front of a selector
   makes the rule win wherever this file is imported. */
html:root {
  --agent: #4f46e5;
  --agent-ink: #ffffff;
}

/* The chat: its own corners and typeface. */
html .wa-chat {
  --wa-chat-radius: 10px;
  --wa-chat-font: "Inter", system-ui, sans-serif;
}

Import it in the root layout, with the stylesheets you already have:

import "@webmcp-agents/core/cursor.css";
import "./globals.css";
import "./agent.css"; 
/* One colour for the agent: the arrow, the tag, the rings and the
   chat's accent all follow --agent. `html` in front of a selector
   makes the rule win wherever this file is imported. */
html:root {
  --agent: #4f46e5;
  --agent-ink: #ffffff;
}

/* The chat: its own corners and typeface. */
html .wa-chat {
  --wa-chat-radius: 10px;
  --wa-chat-font: "Inter", system-ui, sans-serif;
}

Link it from the root route, with the stylesheets you already have:

import agentCss from "../agent.css?url"; 

// In head(), in `links`:
{ rel: "stylesheet", href: agentCss }, 
/* One colour for the agent: the arrow, the tag, the rings and the
   chat's accent all follow --agent. `html` in front of a selector
   makes the rule win wherever this file is imported. */
html:root {
  --agent: #4f46e5;
  --agent-ink: #ffffff;
}

/* The chat: its own corners and typeface. */
html .wa-chat {
  --wa-chat-radius: 10px;
  --wa-chat-font: "Inter", system-ui, sans-serif;
}

Import it in your layout, with the stylesheet you already have:

---
import "@webmcp-agents/core/cursor.css";
import "../agent.css"; 
---

Every selector in the file starts with html. The library’s own rules are written on :root and .wa-chat, and between two rules of the same weight the one that loads last wins, which depends on how your framework orders stylesheets. The extra html makes yours heavier, so they win wherever the file is imported.

The cursor

--agent is the agent’s colour. The arrow and the name tag are filled with it, and everything else is worked out from it: the focus ring and outlines, the soft fill of the ripple and the halo, the colour of the waiting state. Set the others only when you want them to differ.

Property What it colours Default
--agent The arrow and the name tag. #111111
--agent-ink The text on the name tag. #ffffff
--agent-strong The focus ring, the ripple’s edge and the dashed outlines. --agent
--agent-wait The same parts while the cursor waits for the person’s click. --agent
--agent-edge A thin light line around the ring and the ripple, so a dark agent shows on a dark page. white at 60%

Set them on the root element (html:root, as in the example). The soft fills are computed there, so --agent set on a deeper element does not reach them.

The name in the tag is not CSS: it is the name option of the visuals (installAgentVisuals). Motion is not yours to restyle either: the cursor writes its own position every frame, and it already honours prefers-reduced-motion.

The chat

The chat reads --agent for its accent: the launcher, the send button, the person’s own messages, focus outlines. Its other properties are set on its host element, .wa-chat:

Property What it sets Default (light)
--wa-chat-accent, --wa-chat-accent-ink The accent and the text on it, when the chat should not follow the cursor. --agent, --agent-ink
--wa-chat-bg, --wa-chat-fg The panel and its text. #ffffff, #111111
--wa-chat-muted Secondary text. #5f6368
--wa-chat-line, --wa-chat-soft Borders, and the fill of chips and tool calls. black at 10% and 5%
--wa-chat-radius The panel’s corners. 14px
--wa-chat-font The typeface. the system font
--wa-chat-gap The distance from the corner of the window. 20px

To give the chat a different accent from the cursor (in light; dark mode has its own):

html .wa-chat {
  --wa-chat-accent: #0f766e;
  --wa-chat-accent-ink: #ffffff;
}

Dark mode

The chat has a dark look of its own. It turns on with the system setting (prefers-color-scheme), or with data-theme="dark" on the chat or any element around it; data-theme="light" keeps it light. So a site with its own theme switch that writes data-theme on <html> needs nothing more.

The accent adapts by itself. On the dark panel it is a light tint of --agent with dark text on it: the default near-black agent becomes a light grey, a brand blue a light blue. You do not set a second colour for dark.

What you changed on .wa-chat yourself applies in light only, since the chat’s dark rules are heavier than html .wa-chat. That goes for a surface (--wa-chat-bg, --wa-chat-fg) and for an accent of the chat’s own. Give each its dark partner, under the same condition the chat uses:

html[data-theme="dark"] .wa-chat {
  --wa-chat-bg: #0f172a;
  --wa-chat-fg: #e2e8f0;
  --wa-chat-accent: #5eead4;
}

A site that follows the system setting instead wraps the same rule in @media (prefers-color-scheme: dark).

The cursor has no dark variant to switch: the arrow carries a white edge and the ring a light one, so it reads on both.

One part of the chat

Every part of the chat has a class that starts with wa-chat__ (wa-chat__launcher, wa-chat__panel, wa-chat__header, wa-chat__bubble, wa-chat__composer, wa-chat__send, wa-chat__tool). The stylesheet sits outside any cascade layer and most of its rules are a single class, so a selector with html in front overrides them:

html .wa-chat__launcher {
  border-radius: 12px;
}

Prefer the properties where one exists: the class names are the chat’s own markup and follow it when it changes. A rule of the chat that is longer than one class (a part in one state, such as a docked panel) needs your selector to name that state too. For a chat built from your own components instead, see shadcn chat blocks.

Try it

Start the app and call a tool, from the chat or from the devtools. The arrow, its name tag and the ring around the field it types into are in your colour, and so are the chat’s launcher and send button. Switch your system to dark: the chat’s panel turns dark and its buttons take a light tint of your colour.

If nothing changes, the file is not loaded: check the import in the view above.

Options you’ll use most

Property Set on What it is for
--agent html:root The agent’s colour, for the cursor and the chat’s accent.
--agent-ink html:root Text on the name tag and on the chat’s accent.
--agent-strong html:root Rings and outlines in another shade.
--wa-chat-accent html .wa-chat An accent for the chat alone; add a dark partner.
--wa-chat-bg, --wa-chat-fg html .wa-chat The chat’s panel and text; add a dark pair.
--wa-chat-radius html .wa-chat The chat’s corners.
--wa-chat-font html .wa-chat The chat’s typeface.

Every property, class and state: cursor.css and <AgentChat> theming.

Was this page helpful?