-
Notifications
You must be signed in to change notification settings - Fork 16
Description
Overview
Add support for custom footer slots on bot messages to enable developers to add action buttons (copy, regenerate, share, etc.) alongside existing feedback controls.
Problem Statement
Users want to add custom action buttons to the footer of bot messages, but currently there's no straightforward way to inject custom UI elements into this area. Common use cases include:
- Copy button: Copy message content to clipboard
- Regenerate button: Re-run the query to get a new response
- Share button: Share message content via external services
- Custom actions: Application-specific actions related to a message
Proposed Solution
Extend GenericItemMessageOptions to support custom footer slots, following the same pattern as the existing feedback option.
Type Definitions
export interface GenericItemMessageOptions {
feedback?: GenericItemMessageFeedbackOptions;
custom_footer_slot?: GenericItemCustomFooterSlotOptions; // NEW
}
export interface GenericItemCustomFooterSlotOptions {
/**
* Unique identifier for this footer slot. Used to match with the render function.
*/
slot_name: string;
/**
* Whether to show the custom footer slot.
*/
is_on?: boolean;
/**
* Optional additional data to pass to the render function. This can contain
* any custom metadata that the frontend needs to render the footer appropriately.
*/
additional_data?: Record<string, unknown>;
}New Render Prop
Add a new render prop to ChatContainerProps:
interface ChatContainerProps {
// ... existing props
/**
* Render function for custom footer slots. Called for each message that has
* custom_footer_slot configured in its message_item_options.
*/
renderMessageFooter?: (
slotName: string,
message: MessageResponse,
messageItem: GenericItem,
instance: ChatInstance,
additionalData?: Record<string, unknown>
) => ReactNode | null;
}Usage Example
Backend/Message Processing:
{
"response_type": "text",
"text": "Here's your answer",
"message_item_options": {
"feedback": {
"is_on": true,
"id": "feedback-1"
},
"custom_footer_slot": {
"is_on": true,
"slot_name": "footer-msg-123",
"additional_data": {
"allow_regenerate": true,
"allow_copy": true,
"custom_action_url": "https://example.com/share"
}
}
}
}Frontend:
<ChatContainer
renderMessageFooter={(slotName, message, messageItem, instance, additionalData) => {
return (
<div className="custom-footer-actions">
{additionalData?.allow_copy && (
<button
onClick={() => {
navigator.clipboard.writeText(messageItem.text);
}}
>
Copy
</button>
)}
{additionalData?.allow_regenerate && (
<button
onClick={() => {
instance.send({ text: message.input.text });
}}
>
Regenerate
</button>
)}
{additionalData?.custom_action_url && (
<button
onClick={() => {
window.open(additionalData.custom_action_url, '_blank');
}}
>
Share
</button>
)}
</div>
);
}}
/>Design Rationale
Why This Approach?
- Consistent with existing patterns: Follows the same structure as
feedbackinmessage_item_options - Clear separation of concerns: Message structure controls "where" (which messages get footers), render prop controls "what" (the actual content)
- Per-message control: Backend or frontend message processing can decide which messages get footer slots
- Performance: Only creates slots for messages that explicitly opt-in
- Flexible metadata:
additional_dataallows backend to pass custom configuration without changing the type definition - Future-proof: Natural evolution path when native controls (copy, regenerate) are added
Why additional_data?
The additional_data field provides flexibility for:
- Backend to control which actions are available per message
- Passing custom URLs, IDs, or configuration
- Enabling/disabling specific actions based on message context
- Supporting application-specific metadata without type changes
Future Evolution Path
When copy/regenerate become native controls, they can be added to the same structure:
export interface GenericItemCustomFooterSlotOptions {
slot_name?: string; // For custom content (optional when using native controls)
is_on?: boolean;
show_copy?: boolean; // Native copy button
show_regenerate?: boolean; // Native regenerate button
additional_data?: Record<string, unknown>; // Still available for custom controls
}This allows:
- Custom content only
- Native controls only
- Both custom content and native controls together
- Custom metadata for either approach
Implementation Considerations
Rendering Location
The custom footer slot should appear:
- After the main message content
- Alongside or near the feedback buttons
- Before any chain-of-thought or other metadata
Slot Management
Similar to how user_defined responses work:
- When a message with
custom_footer_slot.is_on = trueis received, create a slot element - Use the
slot_nameto uniquely identify the slot - Call
renderMessageFooterwith the slot context andadditional_data - Render the returned React content into the slot via portal
Web Component Support
Ensure this works with both:
<ChatContainer>(React)<cds-aichat-container>(Web Component)
Related Code References
- Feedback implementation:
MessageTypeComponent.tsx:691-886 - Message item options:
Messages.ts:463 - User defined responses:
UserDefinedResponse.tsx - Writeable elements:
WriteableElement.tsx
Open Questions
- How do we handle if the footer content is too large?
Success Criteria
- Developers can add custom footer slots via
message_item_options.custom_footer_slot -
renderMessageFooterprop works in both React and Web Component implementations -
additional_datais properly passed through to the render function - Footer slots appear in the correct location relative to feedback buttons
- Performance is acceptable (no unnecessary slot creation)
- Documentation includes usage examples with
additional_data - Demo/examples showcase common use cases (copy, regenerate, conditional actions)
- Design accommodates future native controls without breaking changes
Metadata
Metadata
Assignees
Labels
Type
Projects
Status