Theming
Erato supports extensive theming capabilities to match your brand identity. You can customize colors, logos, and assistant avatars.
Theme Configuration
Themes are configured in the backend configuration file (erato.toml) and consist of:
- Theme Directory - A folder containing all theme assets
- Theme Configuration - JSON file defining colors and styles
- Static Assets - Logos and avatar images
Setting Up a Custom Theme
- Configure the theme name in
erato.toml:
[frontend]
theme = "my-company"- Create the theme directory in the frontend bundle:
public/custom-theme/my-company/
├── theme.json # Theme configuration
├── fonts.css # Optional custom fonts
├── theme.css # Optional shell-level polish
├── logo.svg # Application logo (light mode)
├── logo-dark.svg # Application logo (dark mode, optional)
├── assistant-avatar.svg # Assistant avatar (optional)
└── locales/ # Custom translations (optional)
├── en/
│ └── messages.po
└── de/
└── messages.poTheme Structure
theme.json
The theme.json file defines the color scheme for both light and dark modes:
{
"name": "My Company Theme",
"theme": {
"light": {
"colors": {
"background": {
"primary": "#ffffff",
"secondary": "#f5f5f5",
"tertiary": "#ffffff"
},
"shell": {
"page": "#f5f5f5",
"chatInput": "#ffffff",
"modal": "#ffffff"
},
"message": {
"assistant": "#f5f5f5"
},
"foreground": {
"primary": "#000000",
"accent": "#0066cc"
},
"overlay": {
"modal": "rgba(15, 23, 42, 0.5)"
},
"avatar": {
"assistant": {
"background": "#0066cc",
"foreground": "#ffffff"
},
"user": {
"background": "#666666",
"foreground": "#ffffff"
}
}
},
"radius": {
"shell": "0.75rem",
"input": "1rem",
"modal": "0.5rem"
},
"spacing": {
"message": {
"paddingX": "1rem",
"paddingY": "1rem",
"gap": "1.5rem"
}
},
"layout": {
"chat": {
"contentMaxWidth": "48rem",
"inputMaxWidth": "56rem"
}
}
},
"dark": {
"colors": {
"background": {
"primary": "#1a1a1a",
"secondary": "#2d2d2d"
},
"foreground": {
"primary": "#ffffff",
"accent": "#4d94ff"
},
"avatar": {
"assistant": {
"background": "#4d94ff",
"foreground": "#ffffff"
},
"user": {
"background": "#888888",
"foreground": "#ffffff"
}
}
}
}
}
}Typed Theme Tokens
The typed theme contract is grouped semantically so starter themes can express shell styling without immediately falling back to theme.css or custom components.
colors.shellcovers app, page, sidebar, chat shell, modal, and dropdown surfacescolors.messagecovers user and assistant message surfaces plus shared hover and controls surfacescolors.overlaycovers backdrops such as the modal overlayradiuscovers base, shell, input, message, modal, and pill radiispacingcovers shell, message, controls, sidebar density, and chat input spacingelevationcovers shell, input, modal, and dropdown shadowslayoutcovers chat content width, chat input width, and sidebar width
Existing theme JSON can omit these new groups. When a theme does not provide them yet, the corresponding CSS variables fall back to the built-in theme defaults until they are explicitly overridden.
Optional Stylesheets
Theme packs can include these optional sibling stylesheets beside theme.json:
fonts.cssloads after the runtime CSS variables fromtheme.jsontheme.cssloads afterfonts.css
If VITE_THEME_CONFIG_PATH or THEME_CONFIG_PATH points to a specific theme.json, these stylesheets are resolved relative to that exact file path. Otherwise they are resolved from the active theme directory selected through VITE_THEME_PATH, THEME_PATH, VITE_CUSTOMER_NAME, or THEME_CUSTOMER_NAME.
theme.css should stay constrained to theme-level visual polish. Prefer root selectors like html[data-theme="light"], html[data-theme="dark"], and CSS custom properties. Avoid deep DOM selectors or overrides tied to Tailwind utility classes.
Stable Styling Hooks
For shell-level overrides in theme.css, prefer the app-owned data-ui and data-role hooks over DOM-depth selectors or Tailwind class names.
data-ui="app-shell"data-ui="page-shell"data-ui="sidebar"data-ui="sidebar-header"data-ui="sidebar-footer"data-ui="chat-history-list"data-ui="chat-history-item"data-ui="chat-header"data-ui="chat-body"data-ui="chat-input-shell"data-ui="chat-input-controls"data-ui="chat-message"data-ui="message-controls"data-ui="modal-overlay"data-ui="modal-shell"data-ui="dropdown-panel"
Messages also expose data-role="user" and data-role="assistant" on the message shell.
Custom Logos
Place logo files in your theme directory:
logo.svg- Main application logo (required)logo-dark.svg- Dark mode logo (optional, falls back tologo.svg)
Custom Language Files
You can customize translation strings to match your brand’s tone and terminology. This is particularly useful for:
- Changing the assistant name (e.g., “Your Company KI Assistent”)
- Choosing formal vs. informal forms of address (e.g., “Du” vs. “Sie” in German)
- Adapting welcome screen messages
Directory Structure
Create language files in your theme directory:
public/custom-theme/my-company/
├── theme.json
├── logo.svg
├── assistant-avatar.svg
└── locales/
├── en/
│ └── messages.po
├── de/
│ └── messages.po
└── fr/
└── messages.poAvailable Branding Translation IDs
These translation IDs are designed for brand customization and have stable IDs guaranteed across versions:
| ID | Purpose | Default (en) | Default (de) |
|---|---|---|---|
branding.assistant_name | The name/label shown for AI messages | ”Assistant" | "Assistent” |
branding.user_form_of_address | Generic label for user messages (fallback when no user name available) | “You" | "Du” |
branding.welcomeScreen.title | Welcome screen heading | ”Welcome to AI Assistant" | "Willkommen beim KI-Assistenten” |
branding.welcomeScreen.subtitle | Welcome screen subheading | ”Get expert help…" | "Erhalten Sie Expertenunterstützung…” |
branding.welcomeScreen.description | Welcome screen description text | ”Ask questions…" | "Stellen Sie Fragen…” |
branding.page_title_suffix | Browser tab title suffix | ”LLM Chat" | "" |
Example: Custom Translations
messages.po (for German):
msgid ""
msgstr ""
"Language: de\n"
#. js-lingui-explicit-id
#: src/components/ui/Chat/ChatMessage.tsx
msgid "branding.assistant_name"
msgstr "Your Company KI Assistent"
#. js-lingui-explicit-id
#: src/components/ui/Chat/ChatMessage.tsx
msgid "branding.user_form_of_address"
msgstr "Sie"Note: The
.pofiles are the source of truth. In development, you can edit both, but only.pofiles should be version controlled.For technical details on how the translation override system works, see Internationalization (i18n).
User Display Name Priority
When displaying user messages, the system follows this priority:
- User’s actual name (from
userProfile.name) - e.g., “Daniel Schmidt” - Form of address (
branding.user_form_of_address) - e.g., “Du”, “Sie”, “You”
This allows personalization when user identity is known, while maintaining your brand’s preferred formality level for anonymous users.
Custom Icons
Erato allows you to customize icons throughout the application, including file type icons, status indicators, and action buttons. You can either select from the 1,300+ icons in the iconoir library or provide your own custom SVG files.
Configuration
Add an icons section to your theme.json:
{
"name": "My Company Theme",
"theme": { ... },
"icons": {
"fileTypes": {
"pdf": "MultiplePages",
"image": "MediaImage",
"video": "./icons/custom-video.svg"
},
"status": {
"info": "InfoCircle",
"warning": "WarningCircle",
"error": "Xmark",
"success": "CheckCircle"
},
"actions": {
"copy": "Copy",
"edit": "EditPencil",
"delete": "Trash"
},
"navigation": {
"assistants": "PeopleTag",
"newChat": "EditPencil",
"search": "Search"
}
}
}Icon Value Formats
Iconoir Icon Names - Use the PascalCase name from iconoir.com :
"pdf": "MultiplePages"Custom SVG Files - Use relative paths to SVG files in your theme folder:
"pdf": "./icons/company-pdf.svg"Relative paths (starting with ./) are resolved to /custom-theme/your-company/icons/.
Icon Categories
| Category | Purpose | Keys |
|---|---|---|
fileTypes | File type icons in upload and file preview | pdf, image, document, spreadsheet, presentation, text, code, archive, audio, video, other |
status | Status indicators in alerts and tool calls | info, warning, error, success, in_progress |
actions | Action button icons (future extensibility) | copy, edit, delete, share, plus, close, check, refresh |
navigation | Sidebar navigation menu item icons | assistants, newChat, search |
File Structure with Custom Icons
public/custom-theme/my-company/
├── theme.json
├── logo.svg
├── icons/ # Custom icon SVG files
│ ├── company-pdf.svg
│ ├── company-video.svg
│ └── custom-error.svg
└── locales/Custom SVG Requirements
When creating custom icons:
- Design on a 24×24 pixel grid to match iconoir icons
- Use
currentColorfor fill/stroke to inherit theme colors:<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"> <path d="..." stroke-width="1.5"/> </svg> - Use clean, optimized SVG code
Example with Mixed Icons
{
"icons": {
"fileTypes": {
"pdf": "./icons/brand-pdf.svg",
"image": "MediaImage",
"video": "./icons/brand-video.svg",
"document": "Page"
},
"status": {
"error": "./icons/brand-error.svg",
"success": "CheckCircle",
"warning": "WarningTriangle"
},
"navigation": {
"assistants": "PeopleTag"
}
}
}Page Layout Configuration
Control the horizontal alignment and maximum width of page content through your theme configuration. This applies to Assistant pages (list, create, edit) and the Search page.
Configuration
Add a layout section to your theme.json:
{
"name": "My Company Theme",
"theme": { ... },
"layout": {
"pages": {
"assistants": {
"alignment": "center",
"maxWidth": "4xl"
},
"search": {
"alignment": "center",
"maxWidth": "4xl"
},
"headers": {
"alignment": "center",
"maxWidth": "2xl"
}
}
}
}Alignment Options
| Value | Description |
|---|---|
"left" | Content aligns to the left of the available space |
"center" | Content centers horizontally (default) |
"right" | Content aligns to the right of the available space |
Max Width Options
| Value | Pixel Width | Description |
|---|---|---|
"2xl" | 672px | Narrow width (default for headers) |
"4xl" | 896px | Standard width (default for pages) |
"6xl" | 1152px | Wide width |
"full" | 100% | Full available width (minus padding) |
Page Types
| Page Type | Controls |
|---|---|
assistants | Assistant list, create, and edit pages |
search | Search page results |
headers | Page header sections (titles and subtitles) |
Examples
Left-aligned with wide content:
{
"layout": {
"pages": {
"assistants": {
"alignment": "left",
"maxWidth": "6xl"
},
"search": {
"alignment": "left",
"maxWidth": "6xl"
},
"headers": {
"alignment": "left",
"maxWidth": "4xl"
}
}
}
}Full-width layout:
{
"layout": {
"pages": {
"assistants": {
"alignment": "center",
"maxWidth": "full"
}
}
}
}Mixed configuration:
{
"layout": {
"pages": {
"assistants": {
"alignment": "left",
"maxWidth": "6xl"
},
"search": {
"alignment": "center",
"maxWidth": "4xl"
}
}
}
}Default Behavior
If no layout configuration is provided, the system uses these defaults:
- Alignment:
center - Headers max-width:
2xl(672px) - Pages max-width:
4xl(896px)
This ensures backward compatibility with existing themes.
Custom Assistant Avatar
You can customize the assistant’s profile picture by adding an assistant-avatar.svg (or other image format) to your theme directory.
Using the Theme Directory
When you have a theme configured, place the avatar file in:
public/custom-theme/my-company/assistant-avatar.svgThe avatar will be automatically detected and used.
Using Additional Environment Configuration
You can also override the assistant avatar path using the additional_environment configuration:
[frontend]
theme = "my-company"
additional_environment = { "THEME_ASSISTANT_AVATAR_PATH" = "/custom-theme/my-company/assistant-avatar.svg" }Supported Image Formats
- SVG (recommended for scalability and quality)
- PNG, JPG, or other browser-supported image formats
Fallback Behavior
If no custom avatar is provided, the assistant will display with:
- A colored circle using the theme’s
avatar.assistant.backgroundcolor - The letter “A” in the
avatar.assistant.foregroundcolor
Environment Variables
You can also configure theme assets using environment variables (useful for development):
VITE_CUSTOMER_NAME- Theme directory nameVITE_LOGO_PATH- Override logo path (light mode)VITE_LOGO_DARK_PATH- Override logo path (dark mode)VITE_ASSISTANT_AVATAR_PATH- Override assistant avatar path
Deployment
Docker
Mount your theme directory into the container:
docker run -v ./my-theme:/app/public/custom-theme/my-company erato-imageKubernetes
Use a ConfigMap to store your theme:
apiVersion: v1
kind: ConfigMap
metadata:
name: erato-theme
data:
theme.json: |
{
"name": "My Theme",
"theme": { ... }
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: erato
spec:
template:
spec:
containers:
- name: erato
volumeMounts:
- name: theme
mountPath: /app/public/custom-theme/my-company
volumes:
- name: theme
configMap:
name: erato-themeFor logos and avatars (binary files), use an init container or a PersistentVolume.
See Also
- Internationalization (i18n) - Language support and how translation overrides work technically
- Configuration Reference - Complete configuration options
- Frontend README - Detailed theme development guide