@yaebal/keyboard
fluent inline and reply keyboard builders.
install
pnpm add @yaebal/keyboardinline keyboard
InlineKeyboard builds an inline_keyboard markup. buttons accumulate
into the current row; call .row() to start a new one. call .build() to get the final InlineKeyboardMarkup object to pass as reply_markup.
import { Bot } from "@yaebal/core";
import { InlineKeyboard } from "@yaebal/keyboard";
const bot = new Bot(process.env.BOT_TOKEN!);
bot.command("menu", (ctx) => {
const kb = new InlineKeyboard()
.text("ban", "action:ban")
.text("warn", "action:warn")
.row()
.url("view profile", "https://t.me/username")
.build();
return ctx.reply("choose an action:", { reply_markup: kb });
});reply keyboard
Keyboard builds a keyboard markup. same row model as InlineKeyboard. flags resized() and oneTime() are
only included in the output when set to true.
import { Keyboard } from "@yaebal/keyboard";
bot.command("start", (ctx) => {
const kb = new Keyboard()
.text("yes")
.text("no")
.row()
.requestContact("share phone")
.resized()
.oneTime()
.build();
return ctx.reply("ready?", { reply_markup: kb });
});web app and switch inline
const kb = new InlineKeyboard()
.webApp("open app", "https://example.com")
.row()
.switchInline("share", "my query")
.build();api
InlineKeyboard
| method | signature | description |
|---|---|---|
text | (label: string, data: string) => this | button with callback_data |
url | (label: string, url: string) => this | button that opens a URL |
webApp | (label: string, url: string) => this | button that opens a Telegram Web App |
switchInline | (label: string, query?: string) => this | switch to inline mode; query defaults to "" |
row | () => this | end the current row; no-op if the row is empty |
build | () => InlineKeyboardMarkup | returns the finished markup; does not mutate the builder |
Keyboard
| method | signature | description |
|---|---|---|
text | (label: string) => this | plain text button |
requestContact | (label: string) => this | button that requests the user's phone number |
requestLocation | (label: string) => this | button that requests the user's location |
row | () => this | end the current row; no-op if the row is empty |
resized | (value?: boolean) => this | set resize_keyboard; defaults to true |
oneTime | (value?: boolean) => this | set one_time_keyboard; defaults to true |
build | () => ReplyKeyboardMarkup | returns the finished markup; does not mutate the builder |
types
| export | description |
|---|---|
InlineKeyboardMarkup | shape returned by InlineKeyboard.build() |
InlineKeyboardButton | single button in an inline keyboard |
ReplyKeyboardMarkup | shape returned by Keyboard.build() |
KeyboardButton | single button in a reply keyboard |
.build() always returns a snapshot. mutating the builder after
calling .build() does not affect the already-returned markup — the rows are
cloned at build time. a trailing
.row() before .build() is safe — an
empty in-progress row is not emitted, so you can end every row with .row() without producing a blank final row.