Design the embed visually in the dashboard and have it apply automatically, or export the props and pin them in your code.
The appearance editor in the dashboard is the recommended way to customize the launcher, theme, typography, composer, and start screen against a live preview. Changes are saved with the project and applied at runtime, so restyling a deployed agent does not require a release.
You can also pass any of it as props instead. Props always win, so the two approaches compose rather than compete.
Choose Auto, English, or Español in the editor's Default language setting. The Edit and preview tabs keep separate greetings, subtitles, composer placeholders, disclaimers, and suggested prompts for each language. Existing custom text remains English; add Spanish copy explicitly. Missing Spanish fields use built-in translations, and untranslated suggested prompts stay hidden.
With Auto, the embed uses the first supported language in each visitor’s browser preferences, falling back to English. The editing tabs still select which language you edit and preview without changing the default.
Override the saved language for an individual user with the SDK:
<HeroUIAgent agentId="..." getAuthToken={getAuthToken} locale="es-AR" />The locale order is the SDK prop, then the agent's saved default, then English. With remoteConfig={false}, the SDK locale or English applies. Regional English and Spanish tags control formatting while sharing the English or neutral Latin American Spanish copy; unsupported languages use English. Explicit SDK text takes precedence over saved translations, including empty strings and disclaimer: false.
The interface language is separate from the response language. AI replies follow the latest substantive user message, use the preceding conversational language for ambiguous follow-ups, and fall back to the configured locale. Explicit requests for another language are honored. Changing the SDK locale updates controls and subsequent submissions; existing messages and conversation titles stay unchanged.
Set locale="auto" to detect browser language in an integration. With remote configuration disabled, pass custom copy through translations, keyed by base language (for example, {en: {greeting: "Hello"}, es: {greeting: "Hola"}}). Explicit composer and start-screen text still takes precedence.
The dashboard and “Powered by” branding stay in English. Browser detection only applies to Auto; customer copy and historical content are never automatically rewritten.
The embed resolves each setting in this order, so the last one that defines a value wins:
HeroUIAgent — anything you write in code.Because the merge happens field by field, a partial override stays partial. Pinning your brand accent in code keeps the launcher icon, radius, greeting, and font that the dashboard supplies:
<HeroUIAgent
getAuthToken={getAuthToken}
agentId={process.env.HEROUI_AGENT_ID!}
// Everything else still comes from the dashboard.
appearance={{theme: {colors: {accent: "#7c3aed"}}}}
/>When appearance needs to ship with your application, disable the saved dashboard configuration and pass the experience as props:
<HeroUIAgent
getAuthToken={getAuthToken}
agentId={process.env.HEROUI_AGENT_ID!}
remoteConfig={false}
appearance={{
viewMode: "floating",
launcher: {position: "bottom-right"},
theme: {
colorScheme: "system",
colors: {
accent: {light: "#7c3aed", dark: "#a78bfa"},
},
radius: "round",
typography: {
baseSize: 15,
fontFamily: "Inter, sans-serif",
},
},
}}
composer={{placeholder: "Ask about your workspace..."}}
startScreen={{
greeting: "How can I help?",
prompts: ["Summarize recent activity", "Show my open tasks"],
subtitle: "Live answers grounded in your workspace.",
}}
/>The Setup panel generates this shape for you when you turn on Inline configuration. Use it when appearance changes should go through code review and deploy with the application.
| Dashboard | Inline props | |
|---|---|---|
| Changing a color | Takes effect on the next page load | Requires a deploy |
| Reviewed in pull requests | No | Yes |
| Who can change it | Anyone with dashboard access | Anyone who can ship code |
| Differs per environment | Use a separate project | Use your own config |
Most teams start with the dashboard and pin individual values in code as they become load-bearing.
Use Save changes to apply your draft. Saved appearance reaches visitors on their next page load, within about a minute of saving because configuration is cached at the edge.
Choose Agent layout in the Preview section. The chat-state control above the preview switches between empty, streaming, generated components, sources, activity, approval, and error states.
Work through Launcher, Colors, Typography, and Style. Each control updates the preview immediately.
Open Code in the toolbar. The Setup panel generates a complete embed for vanilla JavaScript, Next.js, Vite, TanStack Start, or React Router.
By default the snippet is minimal — identity, the token exchange, and your client tools — because everything you designed here is read at runtime. Turn on Inline configuration to write the whole design into the snippet instead, which also sets remoteConfig={false} so the two never disagree.
Copy the snippet into your application. You only need to deploy again if you switch to inline configuration and change the design.
Every editor control maps to a prop on HeroUIAgent — the same name you would use to override it in code. The reference documentation for each group is linked in the last column.
| Editor section | Controls | Prop |
|---|---|---|
| Preview | Agent layout, Beta badge | appearance.viewMode, showBetaBadge |
| Launcher | Position, custom icon, icon background, custom CSS | appearance.launcher |
| Colors | Accent, background, foreground, surface, secondary surface, overlay, tooltip | appearance.theme.colors |
| Typography | Font family and base size from 12 to 18 pixels | appearance.theme.typography |
| Style | Main surface, component surface, and radius | appearance.surfaceVariant, appearance.componentSurfaceVariant, appearance.theme.radius |
| Streaming | Caret style and text animation | markdown |
| Start screen | Greeting, subtitle, suggested prompts, prompt shortcuts | startScreen |
| Composer | Default model, model picker, placeholder, disclaimer, attachments, dictation, and permissions | composer, permissions |
| Tools | Built-in toolkit switches | See Tools |
| Response actions | Source references plus copy, feedback, and retry buttons | showSources, responseActions |
Accent colors apply to controls, generated UI, focus states, and the launcher unless you give the
launcher its own background. User message bubbles stay neutral: they use the Agent's surface and
foreground tokens (--ha-surface and --ha-fg), not the accent.
Two sections behave differently from the rest, and both are easy to trip over.
Tools is not appearance. The toolkit switches here are the same ones on the Tools page — they are stored with the project and take effect server-side, without a deploy. Web, image, and news search also surface as capabilities props in the generated code.
Main surface controls charts, tables, maps, and other primary data containers. Component surface independently controls approval, calendar, commerce, and other response cards. Both are stored with the project and can be pinned in code through appearance.surfaceVariant and appearance.componentSurfaceVariant.
| Mode | Behavior |
|---|---|
| Floating | A launcher button in a bottom corner opens a panel above your page |
| Sidebar | A full-height panel docked to the right edge |
| Chat Bar | A compact prompt centered near the bottom that opens into a conversation card |
The Agent layout cards show where each mode appears on your page. Launcher settings are shown only for Floating.
Chat Bar keeps only the prompt input visible while collapsed. Focusing the prompt opens the conversation smoothly; the header controls collapse it back to the prompt or expand it to full screen. Drafts and conversation history remain available when you reopen it. On mobile, the bar stays compact until opened, and full screen is available from the header.
<HeroUIAgent
appearance={{viewMode: "chat-bar"}}
agentId={process.env.HEROUI_AGENT_ID!}
getAuthToken={getAuthToken}
/>Full screen is an expansion state of Chat Bar and desktop Sidebar, rather than a separate viewMode value. Floating expands into a larger card.
On desktop, opening a floating panel does not lock the host page. Visitors can keep scrolling and
interacting with the page behind it. By default, clicking or tapping outside the panel closes it.
Set appearance.shouldCloseOnInteractOutside to false when visitors need to keep the chat open
while selecting items on the page—for example, when a client tool tracks table rows or canvas
objects. Escape still closes the panel. The full-screen mobile panel is modal and locks background
scroll while open. Chat Bar also supports shouldCloseOnInteractOutside: outside interaction collapses the card to its prompt by default. Its full-screen state locks background scrolling until you exit full screen.
Choose theme variants from the Design system picker. Its Pro collection includes Brutalism, Glass, and Mouve alongside the prebuilt and saved design systems.
A variant ships inside the hosted Agent UI. Selecting one in the dashboard updates the iframe on the next reload; the customer application does not need another package or stylesheet import.
The stylesheet is prescoped to the agent root, so it restyles the panel without touching the rest of your page. Only import the one variant you selected — each sheet styles the agent surface directly, so loading several makes the last one win.
This import is required even with the minimal snippet. A stylesheet is not something the embed can fetch on your behalf, so switching variants in the dashboard is the one appearance change that also needs a code change.
Pro variants and saved design systems require an active Pro license, which is what grants access
to the @heroui-pro/react package. The editor shows an upgrade prompt rather than failing
silently.
The Design system picker applies a prebuilt variant or seeds colors, typography, radius, and theme variant from a saved HeroUI Design System, so the embed inherits your product's tokens instead of being styled twice.
The customizer preview updates immediately when you choose a different design system, including its accent, typography, radius, and theme variant.
The seeded values are a snapshot. Editing any color, font, or radius by hand clears the link to the design system — the embed keeps your manual values rather than silently drifting back.
Choosing a non-default typeface makes the embed load that webfont into your page, so a font selected here renders without any work on your side.
The exception is inline configuration: that snippet carries the webfont itself, either as a stylesheet <link> or an @font-face rule. Keep that markup when you paste it, or the family name resolves to a fallback and the embed looks unstyled. The same applies if you set appearance.theme.typography.fontFamily in code — naming a family does not load it.
Reset — or pressing R — returns every appearance value to its default after a confirmation. It does not touch your system prompt, knowledge base, tools, or API keys.
Set a custom icon's rendered size in pixels without changing the button's click target. The default remains 56% of the button, oversized icons are capped to its bounds, and images retain their aspect ratio.
<HeroUIAgent
agentId={agentId}
getAuthToken={getAuthToken}
appearance={{
launcher: {icon: "/brand.svg", iconSize: 36},
panel: {mobile: {presentation: "sheet", height: "75dvh"}},
}}
/>Mobile panels remain full screen by default. The opt-in sheet works with floating and sidebar modes, leaves the page visible above it, and expands to the viewport. Collapsing restores the configured height, which defaults to 75dvh. Numbers are pixels; strings are CSS lengths. The existing appearance.shouldCloseOnInteractOutside setting controls outside dismissal. Sheets do not have drag or snap gestures.
SDK theme colors already accept CSS colors, including rgba(255, 255, 255, 0.5). In the editor, enter RGB/RGBA or hex and adjust opacity. Saved colors use six-digit hex for opaque values or eight-digit hex for alpha; light and dark values keep their own opacity.
Dictation is hidden when the iframe can determine that the page's microphone Permissions Policy blocks it. Detection does not request microphone access. On browsers without policy introspection, the existing click-time permission handling applies. composer={{dictation: false}} always hides dictation.
The editor displays saved defaults. Explicit application props, including permissions={{showPicker: false}}, override them. Removing a prop restores the saved default. The editor cannot inspect configuration running in your application.