Tutorial: implementing custom option buttons in the web chat
This tutorial shows how you might replace the default rendering of an options response with your own custom clickable buttons.
For a complete, working version of the example described in this tutorial, see Custom buttons for watsonx Assistant web chat.
By default, the web chat always displays an options response as a set of clickable buttons (for 4 or fewer options) or as a drop-down list (for 5 or more more options). This example shows the default rendering of an options response with 3 options:
For this tutorial, we will replace this default rendering with larger, card-style buttons:
Because the rendering of an options response cannot be modified, we will do this by intercepting any incoming options responses from the assistant and converting them into custom (user_defined
) responses. We can then implement a custom
rendering for these responses.
-
Create a handler for the
pre:receive
event. In this handler, look for anyoption
responses in the message payload, and convert them intouser_defined
responses.function preReceiveHandler(event) { const message = event.data; if (message.output.generic) { message.output.generic.forEach(messageItem => { if (messageItem.response_type === 'option') { messageItem.response_type = 'user_defined'; } }) } }
-
Create a handler for the
customResponse
event. This handler renders the custom buttons, using a customCardButton
style we can define in the CSS. (You can see the definition of this style in the full example.)function customResponseHandler(event) { const { message, element, fullMessage } = event.data; message.options.forEach((messageItem, index) => { const button = document.createElement('button'); button.innerHTML = messageItem.label; button.classList.add('CardButton'); button.addEventListener('click', () => onClick(messageItem, button, fullMessage, index)); element.appendChild(button); }); }
-
In your
onLoad
event handler, use theon()
instance method to subscribe to thepre:receive
andcustomResponse
events, registering the handlers as callbacks.instance.on({ type: 'customResponse', handler: customResponseHandler }); instance.on({ type: 'pre:receive', handler: preReceiveHandler });
-
Create a click handler to respond when the customer clicks on one of the custom buttons. In the handler, use the
send()
instance method to send a message to the assistant, using the button label as the message text.In addition, we're adding the custom CSS class
CardButton--selected
to the clicked button, changing its appearance to show that it was selected. (This class is also defined in the full example.)function onClick(messageItem, button, fullMessage, itemIndex) { webChatInstance.send({ input: { text: messageItem.label }}); button.classList.add('CardButton--selected'); }
-
If the user reloads the page or navigates to a different page, the web chat reloads from the session history. If this happens, we want to preserve the "selected" state of any clicked buttons.
To do this, in the
onClick
handler, use theupdateHistoryUserDefined
instance method to store a variable in the session history that indicates which button was clicked.webChatInstance.updateHistoryUserDefined(fullMessage.id, { selectedIndex: itemIndex });
Then, in the
customResponse
handler, read this value and use it to set the initial states of the buttons in any custom responses already in the session history.if (fullMessage.history?.user_defined?.selectedIndex === index) { button.classList.add('CardButton--selected'); }
For complete working code, see the Custom buttons for watsonx Assistant web chat example. The example also shows how to disable the buttons in a custom response after the customer has sent a message, which prevents using the buttons to send a message out of order.