Working with custom buttons to drive conversations
If I’ve said anything about bots, it’s that they’re apps. They’re just apps with a conversational interface. This style of interface can be extremely powerful, as it allows the user to better express themselves, or “skip to the end” if they already know what it is they’re trying to accomplish. The problem, though, is without a bit of forethought to the design of the bot it’s easy to wind up back in this scenario, where the user isn’t sure what to do next:
If you’re well versed in the set of commands you can quickly perform any operation you desire. But there is no guidance provided by the system. Just as they’re no guidance provided here:
We need to guide the user.
Buttons exist for a reason. They succinctly show the user what options are available, and can guide the user towards what they’re looking for. In addition, they help reduce the amount of typing required, which is especially important when talking about someone accessing a bot on a mobile device with a tiny keyboard.
The most obvious place where buttons shine is when providing a list of choices for a user to select from. This might be a shipping method, a category for filtering, or, really, any other set of options. To support a list of choices, BotBuilder provides a choice prompt. The choice prompt, as you might expect, provides the user a list of options for them to choose from, and then provides access to that in the next step of the dialog.
The choice prompt limits the user’s response to just the list of options you provide. You can limit the number of times the bot will ask the user for a response before moving onto the next step in the waterfall.
While choice is certainly nice for providing a simple list of options, it does force the user into choosing one of those options. As a result, it’s not as easy to use choice when trying to guide the user with a list of options while also allowing them to type free-form, which is what you’ll want to do when the user first starts a session with the bot. In addition, you don’t get control over the interface provided.
If you wish to customize the list of prompts, you need to set up a card. This can be an Adaptive Card, or one of the built-in cards such as thumbnail or hero. By using a card you can provide a bit more guidance to the channel on how you’d like your list of options to provide.
To allow the user to select from a list of options, you will add buttons to the card. Buttons can be set to either
imBack, meaning the client will send the message back to the bot just as if the user typed it, or
postBack, meaning the client will send the message to the bot without displaying it inside the client. Generally speaking,
imBack is a better choice, as it makes it clear to the user something has happened, and can give the user a clue as to what to type in the future, should they so decide.
The code below is the wrong way to use buttons to provide a list of options, but it’s the most common mistake I see people make when using buttons with Bot Framework.
In the code snippet below, I want you to notice the addition of the buttons using
builder.CardAction.imBack, and the call to
session.send (where the mistake is).
If you added this dialog to a bot and ran it, you’d see the following output:
The mistake, as I mentioned above, is at
session.send. When using
session.send in the middle of a waterfall dialog, the bot is left in a state where it’s not expecting the user to respond. As a result, when the user does respond by clicking on Blue, the bot simply returns back to the current step in the waterfall, and not to the next one. You can click the buttons as long as you’d like, and you’ll see them continuing to pop up.
In order for the bot to be in a state that expects user input and continues to the next step of a waterfall, you must use a prompt. When using buttons inside of a card, you can choose either a
choice prompt. When using a
text prompt, the bot can accept any input in addition to the buttons you provided. This can allow the user to be more free-form as needed.
choice prompts, however, will limit the user to the list of choices, just as if you created it the traditional way mentioned earlier.
As I mentioned at the beginning of this post, one of the keys to a good user experience in a bot is to provide guidance to the user, otherwise you’re just giving them a C-prompt.Again, the easiest way to do this is via buttons.
We’ve already seen that
imBack behaves just as if the user typed the value manually. We can take advantage of this fact by providing the list of options, and ensuring the values match the intents provided in the bot.
You’ll notice in the code sample below I created a bot with two simple dialogs, and the default dialog sends down the buttons inside of a card. By calling
endConversation, the bot sends down the card and closes off the conversation. When the user clicks on a button it’s just as if the user typed in the value, and the bot will then route the request to the appropriate dialog. The user is free at this point to either click one of the provided buttons, or type in whatever command they desire.
The updated bot now performs as displayed below. In the dialog I started by typing test to trigger the bot. I then clicked on Hello, which displayed the Hello Dialog message. I completed the exchange by typing Hello, which, as you see, sent the same Hello Dialog message.
I’ve said it before, and I’ll certainly say it again - buttons exist for a reason. Buttons can help you provide a good UI/UX for users in any type of application, and bots are no exception. You can use buttons to both limit the amount of typing required, and to help guide the user’s experience with the bot.
 This exceedingly long post?