Portal Community

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:

MechanismHow it's wiredWhen to use it
Settings prop
settings.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 provider
HilChatRendererProvider
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:

1

settings.renderers[kind]

If the settings object supplies a renderer for this message's kind, use it.

2

Context provider

Otherwise, if a HilChatRendererProvider above it supplies one for this kind, use that.

3

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:

PropPurpose
messageThe message being rendered — its kind, sender, text/form payload, and send status.
disabledTrue when this turn is read-only (already submitted, or the request has expired).
onFormValuesChangeFor form-kind messages — call this with the current form values as the person fills them in.
settingsThe active settings object, so a custom renderer can reach configuration such as settings.api without needing outside context.
onRetryPresent 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.