Customising the chatbot UI
This template displays an Algolia InstantSearch Chat widget on every page. Most useful changes are about conversation flow: how sources appear, how links open, and how each assistant turn is ordered.
| Piece | File |
|---|---|
| Mount on every page | src/theme/Root.js |
| Chat widget, tools, sources UI | src/components/AlgoliaChat/index.js |
| Layout and brand tokens for chat | src/components/AlgoliaChat/styles.module.css |
| InstantSearch chat stylesheet | docusaurus.config.js → customCss (instantsearch.css/.../chat.css) |
Credentials and agentId also live at the top of AlgoliaChat/index.js. Keep Search-Only keys in the client; never put the Admin API Key here.
How a turn is built
Each assistant reply can include:
- Markdown answer text
- Tool output (search hits from the agent)
- Follow-up prompt suggestions
Upstream InstantSearch often shows tool hits as a carousel of tiles. This template replaces that with a single Sources pill and popover, and CSS reorders the bubble so readers see answer → sources → follow-ups.
Changing how sources appear
Search and recommend tool results use a custom layout in sourceTools:
const sourceTools = {
[SearchIndexToolType]: {layoutComponent: SourcesLayout},
[RecommendToolType]: {layoutComponent: SourcesLayout},
};
<Chat agentId={AGENT_ID} tools={sourceTools} ... />
SourcesLayout is the component that:
- Collects hits from tool parts on the parent message
- Deduplicates by
objectID/url/path - Renders one pill (
1 Source/N Sources) and a popover list of links - Returns
nullfor later tool parts so you do not get a pill per tool call
Change the pill label
Edit the countLabel logic in SourcesLayout:
const countLabel =
items.length === 1 ? '1 Source' : `${items.length} Sources`;
For example use References or Docs used instead of Sources.
Change how each link is labelled
sourceLabel prefers the crawler heading (page H1), then title, then URL. It also strips a | Site title suffix from Docusaurus document titles:
const SITE_TITLE = '3di Docusaurus Template';
Update SITE_TITLE to match title in docusaurus.config.js when you rebrand. Adjust sourceLabel if you want URL paths or section titles instead.
Change the open behaviour
Links in the popover currently open in a new tab and fire a click insight event. To open in the same tab, remove target / rel from the <a> in SourcesLayout. To drop analytics, remove the sendEvent call.
Restore the default InstantSearch tool UI
Remove or empty tools={sourceTools} on <Chat /> if you want the stock search-index carousel and tiles again. You can also delete SourcesLayout and the related CSS under .sources* in styles.module.css.
Changing answer links and markdown
Assistant text is not the InstantSearch default renderer. It uses AssistantText, which compiles markdown and routes anchors through ChatMarkdownLink:
messagesProps={{
assistantMessageProps: {
textComponent: AssistantText,
},
}}
ChatMarkdownLink adds an external-link icon for http(s) URLs and opens them in a new tab. Same-origin or relative links stay in the current tab.
To change that flow:
- Open
src/components/AlgoliaChat/index.js. - Edit
ChatMarkdownLink(icons,target, classes). - Or point
textComponentat your own component with a different markdown pipeline.
Changing message order in the bubble
Tool DOM nodes often arrive before the answer text. This template uses flex order so the written answer stays first:
.root :global(.ais-ChatMessage--left .ais-ChatMessage-tool) {
order: 2;
/* ... */
}
Follow-up suggestions keep a separator under the answer and sources via .ais-ChatPromptSuggestions. Edit those rules if you want sources above the answer, or no rules between blocks.
Hiding InstantSearch chrome you do not use
This site has no dedicated InstantSearch results page, so the tool carousel “View all” control is hidden:
.root :global(.ais-ChatToolSearchIndexCarouselHeaderViewAll) {
display: none;
}
Remove that rule only if you add a full results route and want the control back.
Brand colour (optional)
Primary InstantSearch chrome (trigger accent, selection) follows CSS variables on .root:
--ais-primary-color-rgb: 79, 38, 131;
Dark theme overrides the same variables under html[data-theme='dark']. Prefer conversation-flow changes above for product behaviour; use these tokens when you only need the widget to match --ifm-color-primary.