The InlineKeyboard class simplifies building inline keyboards (interactive button grids attached to messages). Unlike custom keyboards, inline keyboards appear directly below messages and trigger callback queries or open URLs when pressed.
Constructor
Creates a new InlineKeyboard instance.
const keyboard = new InlineKeyboard ( inline_keyboard ?: InlineKeyboardButton [][])
Optional two-dimensional array of inline keyboard buttons. If not provided, starts with an empty keyboard.
Example
import { InlineKeyboard } from 'grammy'
// Empty keyboard
const keyboard = new InlineKeyboard ()
// Pre-initialized keyboard
const keyboard = new InlineKeyboard ([[
{ text: 'Button 1' , callback_data: 'btn1' },
{ text: 'Button 2' , callback_data: 'btn2' }
]])
Properties
The two-dimensional array of buttons that makes up the inline keyboard (read-only).
These methods add buttons to the keyboard and return this for chaining.
text
Adds a callback query button that sends data back to your bot when pressed.
keyboard . text (
text : string | InlineKeyboardButton . AbstractInlineKeyboardButton ,
data ?: string
): InlineKeyboard
The button text to display
Callback data to send back to your bot. Defaults to the button text if omitted.
Example:
const keyboard = new InlineKeyboard ()
. text ( 'Like' , 'like_btn' )
. text ( 'Dislike' , 'dislike_btn' )
// Handle callback
bot . callbackQuery ( 'like_btn' , async ( ctx ) => {
await ctx . answerCallbackQuery ( 'You liked this!' )
})
url
Adds a button that opens a URL when pressed.
keyboard . url (
text : string | InlineKeyboardButton . AbstractInlineKeyboardButton ,
url : string
): InlineKeyboard
The button text to display
HTTP or tg:// URL to open. Can use tg://user?id=<user_id> to mention users.
Example:
const keyboard = new InlineKeyboard ()
. url ( 'Visit Website' , 'https://grammy.dev' )
. url ( 'Open in Telegram' , 'tg://resolve?domain=grammyjs' )
webApp
Adds a button that launches a Web App.
keyboard . webApp (
text : string | InlineKeyboardButton . AbstractInlineKeyboardButton ,
url : string | WebAppInfo
): InlineKeyboard
The button text to display
url
string | WebAppInfo
required
HTTPS URL of the Web App or WebAppInfo object
Example:
const keyboard = new InlineKeyboard ()
. webApp ( 'Open Web App' , 'https://example.com/webapp' )
login
Adds a login button for Telegram Login Widget.
keyboard . login (
text : string | InlineKeyboardButton . AbstractInlineKeyboardButton ,
loginUrl : string | LoginUrl
): InlineKeyboard
The button text to display
loginUrl
string | LoginUrl
required
HTTPS URL for automatic authorization or LoginUrl object with additional options
Example:
const keyboard = new InlineKeyboard ()
. login ( 'Login' , 'https://example.com/auth' )
. login ( 'Login with options' , {
url: 'https://example.com/auth' ,
forward_text: 'Login to Bot' ,
request_write_access: true
})
switchInline
Adds a button that starts an inline query in a selected chat.
keyboard . switchInline (
text : string | InlineKeyboardButton . AbstractInlineKeyboardButton ,
query ?: string
): InlineKeyboard
The button text to display
Inline query string to prefill. Defaults to empty string.
Example:
const keyboard = new InlineKeyboard ()
. switchInline ( 'Share' )
. switchInline ( 'Search cats' , 'cats' )
// User will be prompted to select a chat, then your bot
// receives an inline query update
bot . on ( 'inline_query' , ( ctx ) => {
console . log ( 'Query:' , ctx . inlineQuery . query )
})
switchInlineCurrent
Adds a button that starts an inline query in the current chat.
keyboard . switchInlineCurrent (
text : string | InlineKeyboardButton . AbstractInlineKeyboardButton ,
query ?: string
): InlineKeyboard
The button text to display
Inline query string to prefill. Defaults to empty string.
Example:
const keyboard = new InlineKeyboard ()
. switchInlineCurrent ( 'Search here' , 'dogs' )
switchInlineChosen
Adds a button that starts an inline query with chat type restrictions.
keyboard . switchInlineChosen (
text : string | InlineKeyboardButton . AbstractInlineKeyboardButton ,
query ?: SwitchInlineQueryChosenChat
): InlineKeyboard
The button text to display
query
SwitchInlineQueryChosenChat
Object describing which chats can be picked Allow selecting private chats with users
Allow selecting private chats with bots
Allow selecting group chats
Allow selecting channel chats
Example:
const keyboard = new InlineKeyboard ()
. switchInlineChosen ( 'Share to group' , {
query: 'check this out' ,
allow_group_chats: true
})
copyText
Adds a button that copies text to the clipboard when pressed.
keyboard . copyText (
text : string | InlineKeyboardButton . AbstractInlineKeyboardButton ,
copyText : string | CopyTextButton
): InlineKeyboard
The button text to display
copyText
string | CopyTextButton
required
Text to copy to clipboard
Example:
const keyboard = new InlineKeyboard ()
. copyText ( 'Copy Code' , 'npm install grammy' )
game
Adds a game button. Must be the first button in the first row.
keyboard . game ( text : string | InlineKeyboardButton . AbstractInlineKeyboardButton ): InlineKeyboard
The button text to display
Example:
const keyboard = new InlineKeyboard ()
. game ( 'Play Game' )
pay
Adds a payment button. Must be the first button in the first row and can only be used in invoice messages.
keyboard . pay ( text : string | InlineKeyboardButton . AbstractInlineKeyboardButton ): InlineKeyboard
The button text to display. Substrings ”⭐” and “XTR” will be replaced with a Telegram Star icon.
Example:
const keyboard = new InlineKeyboard ()
. pay ( 'Pay 100 ⭐' )
Styling Methods
These methods modify the last added button.
style
Applies a style to the last added button.
keyboard . style ( style : 'primary' | 'success' | 'danger' ): InlineKeyboard
style
'primary' | 'success' | 'danger'
required
Button style: 'primary' (blue), 'success' (green), or 'danger' (red)
Example:
const keyboard = new InlineKeyboard ()
. text ( 'Delete' , 'delete' ). style ( 'danger' )
. text ( 'Confirm' , 'confirm' ). style ( 'success' )
danger
Applies danger (red) style. Alias for .style('danger').
keyboard . danger (): InlineKeyboard
success
Applies success (green) style. Alias for .style('success').
keyboard . success (): InlineKeyboard
primary
Applies primary (blue) style. Alias for .style('primary').
keyboard . primary (): InlineKeyboard
icon
Adds a custom emoji icon to the last added button.
keyboard . icon ( icon : string ): InlineKeyboard
Unique identifier of the custom emoji
Example:
const keyboard = new InlineKeyboard ()
. text ( 'Home' , 'home' ). icon ( '5368324170671202286' )
Layout Methods
row
Adds a line break to start a new row of buttons.
keyboard . row ( ... buttons : InlineKeyboardButton []): InlineKeyboard
Optional buttons to add to the new row
Example:
const keyboard = new InlineKeyboard ()
. text ( 'A' , 'a' ). text ( 'B' , 'b' ). row ()
. text ( 'C' , 'c' ). text ( 'D' , 'd' )
// Layout:
// [A] [B]
// [C] [D]
add
Adds pre-constructed button objects to the current row.
keyboard . add ( ... buttons : InlineKeyboardButton []): InlineKeyboard
buttons
InlineKeyboardButton[]
required
Button objects to add
toTransposed
Creates a new inline keyboard with rows and columns flipped.
keyboard . toTransposed (): InlineKeyboard
Example:
const original = new InlineKeyboard ()
. text ( 'A' , 'a' ). text ( 'B' , 'b' ). row ()
. text ( 'C' , 'c' ). text ( 'D' , 'd' )
const transposed = original . toTransposed ()
// Original: Transposed:
// [A] [B] [A] [C]
// [C] [D] [B] [D]
toFlowed
Creates a new inline keyboard with buttons reflowed into a given number of columns.
keyboard . toFlowed ( columns : number , options ?: { fillLastRow? : boolean }): InlineKeyboard
Maximum number of buttons per row
Set to true to completely fill up the last row
Example:
const keyboard = new InlineKeyboard ()
. text ( '1' , '1' ). text ( '2' , '2' ). text ( '3' , '3' )
. text ( '4' , '4' ). text ( '5' , '5' )
const flowed = keyboard . toFlowed ( 2 )
// [1] [2]
// [3] [4]
// [5]
clone
Creates a deep copy of the inline keyboard.
keyboard . clone (): InlineKeyboard
append
Appends buttons from other inline keyboards.
keyboard . append ( ... sources : ( InlineKeyboardButton [][] | InlineKeyboard )[]): InlineKeyboard
Inline keyboards or button arrays to append
Static Methods
InlineKeyboard.text
Creates a callback button without adding it to a keyboard.
InlineKeyboard . text ( text : string , data ?: string ): InlineKeyboardButton . CallbackButton
InlineKeyboard.url
Creates a URL button without adding it to a keyboard.
InlineKeyboard . url ( text : string , url : string ): InlineKeyboardButton . UrlButton
InlineKeyboard.from
Creates an inline keyboard from a two-dimensional button array.
InlineKeyboard . from ( source : InlineKeyboardButton [][] | InlineKeyboard ): InlineKeyboard
source
InlineKeyboardButton[][] | InlineKeyboard
required
Button array or existing keyboard to copy
Example:
const button = InlineKeyboard . text ( 'Click' , 'click_data' )
const keyboard = InlineKeyboard . from ([[ button ]])
All other button methods also have static equivalents.
Complete Example
import { Bot , InlineKeyboard } from 'grammy'
const bot = new Bot ( 'YOUR_BOT_TOKEN' )
// Basic inline keyboard
bot . command ( 'start' , async ( ctx ) => {
const keyboard = new InlineKeyboard ()
. text ( '👍 Like' , 'like' ). text ( '👎 Dislike' , 'dislike' ). row ()
. url ( 'Visit Website' , 'https://grammy.dev' )
await ctx . reply ( 'Rate this bot:' , {
reply_markup: keyboard
})
})
// Handle callbacks
bot . callbackQuery ( 'like' , async ( ctx ) => {
await ctx . answerCallbackQuery ( 'Thanks for the like!' )
await ctx . editMessageText ( 'You liked this bot! ❤️' )
})
bot . callbackQuery ( 'dislike' , async ( ctx ) => {
await ctx . answerCallbackQuery ( 'Sorry to hear that!' )
await ctx . editMessageText ( 'You disliked this bot.' )
})
// Paginated keyboard
let currentPage = 0
const totalPages = 5
bot . command ( 'pages' , async ( ctx ) => {
currentPage = 0
await showPage ( ctx , currentPage )
})
async function showPage ( ctx : any , page : number ) {
const keyboard = new InlineKeyboard ()
if ( page > 0 ) {
keyboard . text ( '◀️ Previous' , `page_ ${ page - 1 } ` )
}
keyboard . text ( ` ${ page + 1 } / ${ totalPages } ` , 'noop' )
if ( page < totalPages - 1 ) {
keyboard . text ( 'Next ▶️' , `page_ ${ page + 1 } ` )
}
await ctx . editMessageText ( `Page ${ page + 1 } of ${ totalPages } ` , {
reply_markup: keyboard
})
}
bot . callbackQuery ( /page_ ( \d + ) / , async ( ctx ) => {
const page = parseInt ( ctx . match [ 1 ])
currentPage = page
await ctx . answerCallbackQuery ()
await showPage ( ctx , page )
})
// Dynamic keyboard with styles
bot . command ( 'settings' , async ( ctx ) => {
const keyboard = new InlineKeyboard ()
. text ( '✅ Notifications' , 'toggle_notifications' ). success (). row ()
. text ( '🎨 Theme' , 'theme' ). primary (). row ()
. text ( '🗑 Delete Account' , 'delete' ). danger ()
await ctx . reply ( 'Settings:' , {
reply_markup: keyboard
})
})
bot . start ()
See Also