Inline and Custom Keyboards (built-in)
Your bot may send a number of buttons, either to be displayed underneath a message, or to replace the user’s keyboard. They are called inline keyboards and custom keyboards, respectively. If you think that this is confusing, then that’s because it is. Thank you, Telegram, for this overlapping terminology.
Let us try to clear it up a bit:
Term | Definition |
---|---|
Inline Keyboard | a set of buttons that is displayed underneath a message inside the chat |
Custom Keyboard | a set of buttons that is displayed instead of the user’s system keyboard |
Inline Keyboard button | a button in an inline keyboard, sends a callback query not visible to the user when pressed, sometimes just called inline button |
Custom Keyboard button | a button in a keyboard, sends a text message with its label when pressed, sometimes just called keyboard button |
InlineKeyboard | class in grammY to create inline keyboards |
Keyboard (!) | class in grammY to create custom keyboards |
Note that both custom keyboard buttons and inline keyboard buttons can also have other functions, such as requesting the user’s location, opening a website, and so on. This was omitted for brevity.
It is not possible to specify both a custom keyboard and an inline keyboard in the same message. The two are mutually exclusive. Moreover, the sent kind of reply markup cannot be changed at a later point by editing the message. For example, it is not possible to first send a custom keyboard along with a message, and then edit the message to use an inline keyboard.
Inline Keyboards
Revisit the inline keyboard section in the Introduction for Developers written by the Telegram team.
grammY has a simple and intuitive way to build up the inline keyboards that your bot can send along with a message. It provides a class called InlineKeyboard
for this.
Both
switchInline
andswitchInlineCurrent
buttons start inline queries. Check out the section about Inline Queries for more information about how they work.
Building an Inline Keyboard
Here are three examples how to build an inline keyboard with text
buttons.
You can also use other methods like url
to let the Telegram clients open a URL, and many more options as listed in the grammY API Reference as well as the Telegram Bot API Reference for InlineKeyboard
.
Example 1
Buttons for a pagination navigation can be built like this:
Code
const inlineKeyboard = new InlineKeyboard()
.text("« 1", "first")
.text("‹ 3", "prev")
.text("· 4 ·", "stay")
.text("5 ›", "next")
.text("31 »", "last");
Result
Example 2
An inline keyboard with share button can be built like this:
Code
const inlineKeyboard = new InlineKeyboard()
.text("Get random music", "random").row()
.switchInline("Send music to friends");
Result
Example 3
URL buttons can be built like this:
Code
const inlineKeyboard = new InlineKeyboard().url(
"Read on TechCrunch",
"https://techcrunch.com/2016/04/11/this-is-the-htc-10/",
);
Result
Sending an Inline Keyboard
You can send an inline keyboard directly along a message, no matter whether you use bot
, ctx
, or ctx
:
// Send inline keyboard with message.
await ctx.reply(text, {
reply_markup: inlineKeyboard,
});
Naturally, all other methods that send messages other than text messages support the same options, as specified by the Telegram Bot API Reference. For example, you can edit a keyboard by calling editMessageReplyMarkup
, and passing the new InlineKeyboard
instance as reply
. Specify an empty inline keyboard to remove all buttons underneath a message.
Responding to Clicks
Menu Plugin
The keyboard plugin gives you raw access to the update objects that Telegram sends. However, responding to clicks this way can be tedious. If you are looking for a more high-level implementation of inline keyboards, check out the menu plugin. It makes it simple to create interactive menus.
Every text
button has a string as callback data attached. If you don’t attach callback data, grammY will use the button’s text as data.
Once a user clicks a text button, your bot will receive an update containing the corresponding button’s callback data. You can listen for callback data via bot
.
// Construct a keyboard.
const inlineKeyboard = new InlineKeyboard().text("click", "click-payload");
// Send a keyboard along with a message.
bot.command("start", async (ctx) => {
await ctx.reply("Curious? Click me!", { reply_markup: inlineKeyboard });
});
// Wait for click events with specific callback data.
bot.callbackQuery("click-payload", async (ctx) => {
await ctx.answerCallbackQuery({
text: "You were curious, indeed!",
});
});
Answering All Callback Queries
bot
is useful to listen for click events of specific buttons. You can use bot
to listen for events of any button.
bot.callbackQuery("click-payload" /* , ... */);
bot.on("callback_query:data", async (ctx) => {
console.log("Unknown button event with payload", ctx.callbackQuery.data);
await ctx.answerCallbackQuery(); // remove loading animation
});
It makes sense to define bot
at last to always answer all other callback queries that your previous listeners did not handle. Otherwise, some clients may display a loading animation for up to a minute when a user presses a button that your bot does not want to react to.
Custom Keyboards
First things first: custom keyboards are sometimes just called keyboards, sometimes they’re called reply keyboards, and even Telegram’s own documentation is not consistent in this repect. As a simple rule of thumb, when it isn’t absolutely obvious from the context and not called inline keyboard, it probably is a custom keyboard. This refers to a way to replace the system keyboard by a set of buttons that you can define.
Revisit the custom keyboard section in the Introduction for Developers written by the Telegram team.
grammY has a simple and intuitive way to build up the custom keyboards that your bot can use to replace the system keyboard. It provides a class called Keyboard
for this.
Once a user clicks a text button, your bot will receive the sent text as a plain text message. Remember that you can listen for text message via bot
or bot
.
Building a Custom Keyboard
Here are three examples how to build a custom keyboard with text
buttons.
You can also request the phone number with requestContact
, the location with requestLocation
, and a poll with requestPoll
.
Example 1
Three buttons in one column can be built like this:
Code
const keyboard = new Keyboard()
.text("Yes, they certainly are").row()
.text("I'm not quite sure").row()
.text("No. 😈");
Result
Example 2
A calculator pad can be built like this:
Code
const keyboard = new Keyboard()
.text("7").text("8").text("9").text("*").row()
.text("4").text("5").text("6").text("/").row()
.text("1").text("2").text("3").text("-").row()
.text("0").text(".").text("=").text("+");
Result
Example 3
Four buttons in a grid can be built like this:
Code
const keyboard = new Keyboard()
.text("A").text("B").row()
.text("C").text("D");
Result
Sending a Custom Keyboard
You can send a custom keyboard directly along a message, no matter whether you use bot
, ctx
, or ctx
:
// Send keyboard with message.
await ctx.reply(text, {
reply_markup: keyboard,
});
Naturally, all other methods that send messages other than text messages support the same options, as specified by the Telegram Bot API Reference.
If you want to specify further options with your message, you may need to create your own reply
object. In that case, you have to use keyboard
when passing it to your object.
Resize Custom Keyboard
You can specify the resize
option if you want the custom keyboard to be resized according to the buttons it contains. This will effectively make the keyboard smaller. (Usually, the keyboard will always have the size of the app’s standard keyboard.)
await ctx.reply(text, {
reply_markup: {
resize_keyboard: true,
keyboard: keyboard.build(),
},
});
One-Time Custom Keyboards
You can specify the one
option if you want the custom keyboard to be hidden immediately after the first button was pressed.
await ctx.reply(text, {
reply_markup: {
one_time_keyboard: true,
keyboard: keyboard.build(),
},
});
Input Field Placeholder
You can specify the input
option if you want a placeholder to be shown in the input field as long as the custom keyboard is visible.
const keyboard = new Keyboard().text("LEFT").text("RIGHT");
await ctx.reply(text, {
reply_markup: {
input_field_placehoder: "Send LEFT or RIGHT",
keyboard: keyboard.build(),
},
});
Selectively Send Custom Keyboards
You can specify the selective
option if you want to show the custom keyboard only to those users that are @-mentioned in the text of the message object, and to the sender of the original message in case your message is a reply.
await ctx.reply(text, {
reply_to_message_id: ctx.msg.message_id,
reply_markup: {
selective: true,
keyboard: keyboard.build(),
},
});
Responding to Clicks
As mentioned earlier, all that custom keyboards do is sending regular text messages. Your bot cannot differentiate between ordinary text messages, and text messages that were sent by clicking a button.
Moreover, buttons will always send exactly the message that’s written on them. Telegram does not allow you to create buttons that display one text, but send another. If you need to do this, you should use an inline keyboard instead.
In order to handle the click of a specific button, you can use bot
with the same text as you put on the button. If you want to handle all button clicks at once, you use bot
and inspect ctx
to figure out which button was clicked, or if an ordinary text message was sent.
Removing a Custom Keyboard
Unless you specify one
as described above, the custom keyboard will remain open for the user (but the user can minimize it).
You can only remove a custom keyboard when you send a new message in the chat, just like you can only specify a new keyboard by sending a message. Pass { remove
as reply
like so:
await ctx.reply(text, {
reply_markup: { remove_keyboard: true },
});
Next to remove
, you can again set selective:
in order to remove the custom keyboard for selected users only. This works analogously to selectively sending a custom keyboard.
Plugin Summary
This plugin is built-in into the core of grammY. You don’t need to install anything to use it. Simply import everything from grammY itself.
Also, both the documentation and the API reference of this plugin are unified with the core package.