Skip to main content

Re-establish the Theme Outside the Chat Shell

The SDK's design tokens (--asg-color-*, radii, spacing) are emitted onto the Chatbot container's root. Any SDK component rendered outside that subtree misses them and falls back to the literals baked into each CSS rule — and those literals are light-themed.

How badly it shows depends on the component: a panel like <TaskList> loses the theme's accent and border colors (toggle the demo below and watch the border and spinner), while <FileExplorerPanel> — large and mostly filled surfaces — comes out flat white on a dark page.

Re-establish the Theme Outside the Chat Shell

The SDK's design tokens (--asg-color-*, radii, spacing) are emitted onto the Chatbot container's root. Any SDK component rendered outside that subtree — a consumer-placed <TaskList>, <SubagentList> or <FileExplorerPanel> — misses them and falls back to the literals baked into each rule, which are light-themed. <AsgardThemeScope> re-establishes the same tokens somewhere else.

A TaskList placed outside the Chatbot

import { AsgardThemeScope, FileExplorerPanel } from '@asgard-js/react';

const theme = {
  chatbot: {
    backgroundColor: '#1a1430',
    borderColor: '#6d4aff',
    primaryComponent: { mainColor: '#7c5cff' },
  },
};

<Chatbot theme={theme} {...rest} />

// anywhere outside the chat shell
<AsgardThemeScope theme={theme}>
  <FileExplorerPanel {...panelProps} />
</AsgardThemeScope>

Toggle it: wrapped, the panel's border and spinner take the theme's purple and match the Chatbot on the right; unwrapped, they fall back to the built-in defaults (grey border, amber spinner). Pass the same object you give <Chatbot theme> to <AsgardThemeScope theme> so both surfaces stay in step. It is unnecessary inside <Chatbot> — the shell already scopes the tokens.

Loading chatbot...

Usage

Wrap the components you place outside, passing the same object you give <Chatbot theme>:

import { AsgardThemeScope, FileExplorerPanel } from "@asgard-js/react";

const theme = {
chatbot: {
backgroundColor: "#1a1430",
borderColor: "#6d4aff",
primaryComponent: { mainColor: "#7c5cff" },
},
};

<Chatbot theme={theme} {...rest} />

// anywhere outside the chat shell
<AsgardThemeScope theme={theme}>
<FileExplorerPanel {...panelProps} />
</AsgardThemeScope>

Passing the same object to both is what keeps the two surfaces in step.

Props

<AsgardThemeScope
theme={theme} // same shape as <Chatbot theme>, optional
className="..." // optional
style={{ ... }} // optional
>

Besides the tokens it also establishes the font and box-model baseline these components expect.

When You Need It

SituationNeeded?
The component is inside <Chatbot>No — the shell already scopes the tokens
A self-docked <TaskList> / <SubagentList>Yes
A consumer-placed <FileExplorerPanel>Yes
Anything drawn by renderFooter / renderHeaderNo — those still render inside the shell

The test is simple: is the component rendered inside <Chatbot>'s DOM subtree?

See Also