Custom Renderers
The shipped bubble and inline-form components cover most needs, but your app can replace how any one message kind renders without forking the whole window.
Two Message Kinds, Two Ways to Override
Today there are exactly two message kinds — text and form. Both can
be overridden the same way, using either of two mechanisms:
| Mechanism | How it's wired | When to use it |
|---|---|---|
Settings propsettings.renderers |
A plain object passed straight into the settings prop — no extra setup. |
The default choice — a single <HilChatWindow> instance needs one specific kind rendered differently. |
Context providerHilChatRendererProvider |
Wrap part of your component tree in the provider; every <HilChatWindow> underneath picks it up automatically. |
Your app already uses a similar context-based override for the Form-HIL overlay and wants the same pattern for chat, or you have several chat windows that should all share one override without repeating the settings object. |
Option 1 — Settings Prop
import { defaultChatSettings } from '@bizfirst/hil-ui-chat-window';
import { MyCustomTextBubble } from './MyCustomTextBubble';
const settings = {
...defaultChatSettings,
renderers: {
text: MyCustomTextBubble,
},
};
<HilChatWindow settings={settings} />
Option 2 — Context Provider
import { HilChatRendererProvider, HilChatWindow, defaultChatSettings } from '@bizfirst/hil-ui-chat-window';
import { MyCustomFormBubble } from './MyCustomFormBubble';
<HilChatRendererProvider value={{ form: MyCustomFormBubble }}>
<HilChatWindow settings={defaultChatSettings} />
</HilChatRendererProvider>
Which One Wins?
Both mechanisms can be used at the same time for different kinds without conflict. When deciding how to render one message, the chat window checks, in order:
settings.renderers[kind]
If the settings object supplies a renderer for this message's kind, use it.
Context provider
Otherwise, if a HilChatRendererProvider above it supplies one for this kind, use that.
Shipped default
Otherwise, fall back to the built-in bubble/form renderer.
So an app can mix both — override text via settings while letting form fall through to a context-provided override:
<HilChatRendererProvider value={{ form: MyCustomFormBubble }}>
<HilChatWindow settings={{ ...defaultChatSettings, renderers: { text: MyCustomTextBubble } }} />
</HilChatRendererProvider>
What a Custom Renderer Receives
A renderer for either kind receives the same shape of props:
| Prop | Purpose |
|---|---|
message | The message being rendered — its kind, sender, text/form payload, and send status. |
disabled | True when this turn is read-only (already submitted, or the request has expired). |
onFormValuesChange | For form-kind messages — call this with the current form values as the person fills them in. |
settings | The active settings object, so a custom renderer can reach configuration such as settings.api without needing outside context. |
onRetry | Present only when the message's send failed — call it to re-attempt sending. |
Replacing the Whole Window
Both mechanisms above only replace how one message kind renders inside the shipped shell
(message list, composer, header). If an app needs to replace the layout wholesale — a
completely custom composer or transcript, not just one bubble kind — that's outside the scope
of these two mechanisms; it means wrapping or replacing HilChatWindow itself
rather than overriding through settings or context.