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. |
Inline | 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 Telegram Bot Features 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 Inline
for this.
The buttons added by calling
switch
,Inline switch
, andInline Current switch
start inline queries. Check out the section about Inline Queries for more information on how they work.Inline Chosen
Building an Inline Keyboard
You can build an inline keyboard by creating a new instance of the Inline
class, and then adding buttons you like to it using .text()
and its other methods.
Here is an example:
const inlineKeyboard = new InlineKeyboard()
.text("« 1", "first")
.text("‹ 3", "prev")
.text("· 4 ·", "stay")
.text("5 ›", "next")
.text("31 »", "last");
2
3
4
5
6
Call .row()
if you want to begin a new row of buttons. You can also use other methods like .url()
to let the user’s client open a specific URL or do other cool things. Be sure to check out all methods on the Inline
class.
If you already have an array of strings that you would like to turn into an inline keyboard, you can use a second, alternative style for building inline keyboard instances. The Inline
class has static methods such as Inline
that let you create button objects. In turn, you can create an inline keyboard instance from array of button objects using Inline
.
That way, you can build the above inline keyboard in a functional way.
const labelDataPairs = [
["« 1", "first"],
["‹ 3", "prev"],
["· 4 ·", "stay"],
["5 ›", "next"],
["31 »", "last"],
];
const buttonRow = labelDataPairs
.map(([label, data]) => InlineKeyboard.text(label, data));
const keyboard = InlineKeyboard.from([buttonRow]);
2
3
4
5
6
7
8
9
10
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,
});
2
3
4
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 edit
, and passing the new Inline
instance as reply
. Specify an empty inline keyboard to remove all buttons underneath a message.
Responding to Inline Keyboard 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!",
});
});
2
3
4
5
6
7
8
9
10
11
12
13
14
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
});
2
3
4
5
6
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 respect. 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 Telegram Bot Features 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
You can build a custom keyboard by creating a new instance of the Keyboard
class, and by then adding buttons like to it via .text()
and others. Call .row()
to begin a new row of buttons.
Here is an example:
const keyboard = new Keyboard()
.text("Yes, they certainly are").row()
.text("I'm not quite sure").row()
.text("No. 😈")
.resized();
2
3
4
5
You can also send more powerful buttons that request the user’s phone number or location or do other cool things. Be sure to check out all methods on the Keyboard
class.
If you already have an array of strings that you would like to turn into a keyboard, you can use a second, alternative style for building keyboard instances. The Keyboard
class has static methods such as Keyboard
that let you create button objects. In turn, you can create a keyboard instance from array of button objects using Keyboard
.
That way, you can build the above keyboard in a functional way.
const labels = [
"Yes, they certainly are",
"I'm not quite sure",
"No. 😈",
];
const buttonRows = labels
.map((label) => [Keyboard.text(label)]);
const keyboard = Keyboard.from(buttonRows).resized();
2
3
4
5
6
7
8
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,
});
2
3
4
Naturally, all other methods that send messages other than text messages support the same options, as specified by the Telegram Bot API Reference.
You can also give your keyboard one or more further properties by calling special methods on it. They will not add any buttons, but rather define the behavior of the keyboard. We have already seen resized
in the example above—here are a few more things you can do.
Persistent Keyboards
By default, users see an icon that allows them to show or hide the custom keyboard which your bot set.
You can call persistent
if you want the custom keyboard to always be shown when the regular system keyboard is hidden. That way, users will always see either the custom keyboard or the system keyboard.
new Keyboard()
.text("Skip")
.persistent();
2
3
Resize Custom Keyboard
You can call resized
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.)
new Keyboard()
.text("Yes").row()
.text("No")
.resized();
2
3
4
It does not matter whether you call resized
first, last or somewhere in between. The result will always be the same.
One-Time Custom Keyboards
You can call one
if you want the custom keyboard to be hidden immediately after the first button was pressed.
new Keyboard()
.text("Yes").row()
.text("No")
.oneTime();
2
3
4
It does not matter whether you call one
first, last or somewhere in between. The result will always be the same.
Input Field Placeholder
You can call placeholder
if you want a placeholder to be shown in the input field as long as the custom keyboard is visible.
new Keyboard()
.text("Yes").row()
.text("No")
.placeholder("Decide now!");
2
3
4
It does not matter whether you call placeholder
first, last or somewhere in between. The result will always be the same.
Selectively Send Custom Keyboards
You can call selected
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.
new Keyboard()
.text("Yes").row()
.text("No")
.selected();
2
3
4
It does not matter whether you call selected
first, last or somewhere in between. The result will always be the same.
Responding to Custom Keyboard 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 },
});
2
3
Next to remove
, you can 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.