Skip to main content

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.

Current Count
0
Loading chatbot...

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:

FieldTypePurpose
idstringStable identity (React key, test hook, override target)
iconReactNodeThe glyph; replaced by a spinner while busy
labelstringAccessible label + hover tooltip (required — icon-only buttons must not omit it)
onClick() => voidClick handler
activebooleanToggle "pressed" state (e.g. File Explorer open) → highlight + aria-pressed
busybooleanBusy (e.g. reset in progress) → spinner + disabled
disabledbooleanDisabled
render() => ReactNodeFully 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:

FieldTypeDescription
avatarstringBot avatar URL
titlestringChatbot title
isConnectingbooleanWhether the channel is connecting
isResettingbooleanWhether the channel is resetting
resetChannel() => voidReset the channel
closeChannel() => voidClose the channel
messagesMap<string, ConversationMessage>All messages