Custom Header
Use renderHeader to replace the default chatbot header with your own
React component. Access SDK state via useAsgardContext and react to the
onMessageSent / onReset lifecycle callbacks.
Message Counter
Send any message in the chatbot to see the counter increase in the custom header. Click Reset in the header to clear it.
Code Example
import { Chatbot, useAsgardContext } from "@asgard-js/react";
function MyHeader({ count }: { count: number }) {
const { avatar, resetChannel } = useAsgardContext();
return (
<header>
{avatar && <img src={avatar} alt="" />}
<span>Messages sent: {count}</span>
<button onClick={() => resetChannel?.()}>Reset</button>
</header>
);
}
function Demo() {
const [count, setCount] = useState(0);
return (
<Chatbot
onMessageSent={() => setCount((c) => c + 1)}
onReset={() => setCount(0)}
renderHeader={() => <MyHeader count={count} />}
{...rest}
/>
);
}
renderHeader Receives the Assembled Actions
renderHeader takes an argument rather than nothing:
interface ChatHeaderRendererArgs {
botName: string | null;
title: string | null;
actions: ChatHeaderAction[]; // the assembled right-side actions, built-ins included
renderDefault: () => ReactNode;
}
actions is the already-assembled sequence, the built-in File Explorer toggle included.
Taking over the whole bar does not mean rebuilding those buttons — render from actions:
<Chatbot
renderHeader={({ title, actions, renderDefault }) => (
<header>
<strong>{title}</strong>
{actions.map((action) => (
<button
key={action.id}
onClick={action.onClick}
disabled={action.disabled || action.busy}
aria-pressed={action.active}
title={action.label}
>
{action.render ? action.render() : action.icon}
</button>
))}
</header>
)}
{...rest}
/>
Returning null hides the whole bar. To take over only the title text area, use renderTitle —
see Channel Title.
Adding Your Own Buttons with headerActions
You can add action buttons without taking over the bar at all — headerActions are appended
after the built-ins:
| Field | Type | Purpose |
|---|---|---|
id | string | Stable identity (React key, test hook, override target) |
icon | ReactNode | The glyph; replaced by a spinner while busy |
label | string | Accessible label + hover tooltip (required — icon-only buttons must not omit it) |
onClick | () => void | Click handler |
active | boolean | Toggle "pressed" state (e.g. File Explorer open) → highlight + aria-pressed |
busy | boolean | Busy (e.g. reset in progress) → spinner + disabled |
disabled | boolean | Disabled |
render | () => ReactNode | Fully custom cell (a usage badge, a version dropdown…). Skips the standard button rendering but keeps its slot in the sequence |
useAsgardContext Key Fields
Inside renderHeader, use this hook to access SDK internal state:
| Field | Type | Description |
|---|---|---|
avatar | string | Bot avatar URL |
title | string | Chatbot title |
isConnecting | boolean | Whether the channel is connecting |
isResetting | boolean | Whether the channel is resetting |
resetChannel | () => void | Reset the channel |
closeChannel | () => void | Close the channel |
messages | Map<string, ConversationMessage> | All messages |