Main menu (reply keyboard) โ
A persistent menu on the keyboard below the input field:
ts
import { replyMenu } from 'easytg';
const mainMenu = replyMenu(
[
[replyMenu.button('๐ Catalog', catalog), replyMenu.button('๐งพ Orders', orders)],
[replyMenu.button((locale, t) => t('menu.support'), support)], // a label per language
[replyMenu.webApp('๐ Shop', 'https://shop.example.com')], // opens a Mini App
[replyMenu.close()], // "โ๏ธ Close menu": removes the keyboard
],
{ placeholder: 'Choose from the menu' },
);
const app = new EasyTG({ menu: mainMenu });
bot.command('start', (ctx) => app.showMenu(ctx, 'Welcome!')); // sends a message with the menuTry it โ
A whole bot. On the docs site it runs next to the code, in a Telegram simulator.
- A menu button sends its label as a message. easytg recognises it (in the user's language) and opens the page as a new message, or starts the dialogue. Middlewares run as usual.
- Targets can't require params, because reply buttons only send their label.
- A label can be a function of the user's language:
(locale, t) => โฆ, withtfor your translated messages. replyMenu.webApp(label, url)opens a Mini App (private chats only); what it sends withsendDataarrives as thewebAppDataevent.- Pressing a menu button during a dialogue leaves the dialogue, like a /command.
- A reply keyboard stays in the chat until the bot removes it, even after the bot stops, so offer a way out.
replyMenu.close(label?)adds a button that removes the menu; Telegram needs a message for that, so it sendstexts.menuClosed.app.hideMenu(ctx, text)does the same from code (e.g. a/hidecommand). { persistent: false }lets users collapse the menu into the keyboard icon instead of always showing it.
For /commands and Telegram's command menu (the โฐ button), see Commands.
A message carries either inline buttons or a reply keyboard, never both. So pages keep their inline keyboards, and the menu is set by its own message.