Skip to main content
The Keyboard class simplifies building custom reply keyboards (bottom-of-screen keyboards that replace the system keyboard). These keyboards appear when users interact with your bot and send text responses back when buttons are pressed.

Constructor

Creates a new Keyboard instance.
const keyboard = new Keyboard(keyboard?: KeyboardButton[][])
keyboard
KeyboardButton[][]
Optional two-dimensional array of keyboard buttons. If not provided, starts with an empty keyboard.

Example

import { Keyboard } from 'grammy'

// Empty keyboard
const keyboard = new Keyboard()

// Pre-initialized keyboard
const keyboard = new Keyboard([[
  { text: 'Button 1' },
  { text: 'Button 2' }
]])

Properties

keyboard
KeyboardButton[][]
The two-dimensional array of buttons that makes up the keyboard (read-only).
is_persistent
boolean
Requests clients to always show the keyboard when the regular keyboard is hidden. Defaults to false.
selective
boolean
Show the keyboard only to users mentioned in the text of the message object.
one_time_keyboard
boolean
Hide the keyboard after a button is pressed.
resize_keyboard
boolean
Resize the keyboard according to its buttons. Usually makes the keyboard smaller.
input_field_placeholder
string
Placeholder shown in the input field when the keyboard is active.

Button Methods

These methods add buttons to the keyboard and return this for chaining.

text

Adds a text button that sends its text as a message when pressed.
keyboard.text(text: string, options?: KeyboardButton.CommonButton['style'] | Omit<KeyboardButton.CommonButton, 'text'>): Keyboard
text
string
required
The button text to display
options
string | object
Button style ('primary', 'success', 'danger') or additional button properties
Example:
const keyboard = new Keyboard()
  .text('Simple button')
  .text('Primary button', 'primary')
  .text('With icon', { icon_custom_emoji_id: '5368324170671202286' })

requestUsers

Adds a button that requests users to be shared when pressed.
keyboard.requestUsers(
  text: string | KeyboardButton.CommonButton,
  requestId: number,
  options?: Omit<KeyboardButtonRequestUsers, 'request_id'>
): Keyboard
text
string | object
required
The button text to display
requestId
number
required
A signed 32-bit identifier of the request that will be received back in users_shared service message
options
object
Additional requirements for user selection
Example:
const keyboard = new Keyboard()
  .requestUsers('Select a user', 1)
  .requestUsers('Select up to 5 bots', 2, {
    user_is_bot: true,
    max_quantity: 5
  })

requestChat

Adds a button that requests a chat to be shared when pressed.
keyboard.requestChat(
  text: string | KeyboardButton.CommonButton,
  requestId: number,
  options?: Omit<KeyboardButtonRequestChat, 'request_id'>
): Keyboard
text
string | object
required
The button text to display
requestId
number
required
A signed 32-bit identifier of the request that will be received back in chat_shared service message
options
object
Requirements for chat selection. Defaults to { chat_is_channel: false }.
Example:
const keyboard = new Keyboard()
  .requestChat('Select a group', 1, { chat_is_channel: false })
  .requestChat('Select a channel', 2, { chat_is_channel: true })

requestContact

Adds a button that requests the user’s phone number as a contact.
keyboard.requestContact(text: string | KeyboardButton.CommonButton): Keyboard
text
string | object
required
The button text to display
Example:
const keyboard = new Keyboard()
  .requestContact('Share phone number')

requestLocation

Adds a button that requests the user’s current location.
keyboard.requestLocation(text: string | KeyboardButton.CommonButton): Keyboard
text
string | object
required
The button text to display
Example:
const keyboard = new Keyboard()
  .requestLocation('Share location')

requestPoll

Adds a button that requests the user to create and send a poll.
keyboard.requestPoll(
  text: string | KeyboardButton.CommonButton,
  type?: 'quiz' | 'regular'
): Keyboard
text
string | object
required
The button text to display
type
'quiz' | 'regular'
Type of poll allowed. Omit to allow any type.
Example:
const keyboard = new Keyboard()
  .requestPoll('Create poll')
  .requestPoll('Create quiz', 'quiz')

webApp

Adds a button that opens a Web App.
keyboard.webApp(text: string | KeyboardButton.CommonButton, url: string): Keyboard
text
string | object
required
The button text to display
url
string
required
HTTPS URL of the Web App to be opened
Example:
const keyboard = new Keyboard()
  .webApp('Open App', 'https://example.com/webapp')

Styling Methods

These methods modify the last added button.

style

Applies a style to the last added button.
keyboard.style(style: 'primary' | 'success' | 'danger'): Keyboard
style
'primary' | 'success' | 'danger'
required
Button style: 'primary' (blue), 'success' (green), or 'danger' (red)
Example:
const keyboard = new Keyboard()
  .text('Delete').style('danger')
  .text('Confirm').style('success')

danger

Applies danger (red) style. Alias for .style('danger').
keyboard.danger(): Keyboard

success

Applies success (green) style. Alias for .style('success').
keyboard.success(): Keyboard

primary

Applies primary (blue) style. Alias for .style('primary').
keyboard.primary(): Keyboard

icon

Adds a custom emoji icon to the last added button.
keyboard.icon(icon: string): Keyboard
icon
string
required
Unique identifier of the custom emoji
Example:
const keyboard = new Keyboard()
  .text('Home').icon('5368324170671202286')

Layout Methods

row

Adds a line break to start a new row of buttons.
keyboard.row(...buttons: KeyboardButton[]): Keyboard
buttons
KeyboardButton[]
Optional buttons to add to the new row
Example:
const keyboard = new Keyboard()
  .text('A').text('B').row()
  .text('C').text('D')

// Layout:
// [A] [B]
// [C] [D]

add

Adds pre-constructed button objects to the current row.
keyboard.add(...buttons: KeyboardButton[]): Keyboard
buttons
KeyboardButton[]
required
Button objects to add

Transformation Methods

toTransposed

Creates a new keyboard with rows and columns flipped.
keyboard.toTransposed(): Keyboard
Example:
const original = new Keyboard()
  .text('A').text('B').row()
  .text('C').text('D')

const transposed = original.toTransposed()
// Original:    Transposed:
// [A] [B]      [A] [C]
// [C] [D]      [B] [D]

toFlowed

Creates a new keyboard with buttons reflowed into a given number of columns.
keyboard.toFlowed(columns: number, options?: { fillLastRow?: boolean }): Keyboard
columns
number
required
Maximum number of buttons per row
options
object
Example:
const keyboard = new Keyboard()
  .text('A').text('B').text('C')
  .text('D').text('E')

const flowed = keyboard.toFlowed(2)
// [A] [B]
// [C] [D]
// [E]

clone

Creates a deep copy of the keyboard.
keyboard.clone(keyboard?: KeyboardButton[][]): Keyboard
keyboard
KeyboardButton[][]
Optional button array to use instead of cloning the current one

append

Appends buttons from other keyboards.
keyboard.append(...sources: (KeyboardButton[][] | Keyboard)[]): Keyboard
sources
Array
required
Keyboards or button arrays to append

Configuration Methods

persistent

Makes the keyboard persistent (always shown).
keyboard.persistent(isEnabled?: boolean): Keyboard
isEnabled
boolean
Whether to enable persistence. Defaults to true.
Example:
const keyboard = new Keyboard()
  .text('Button')
  .persistent()

selected

Makes the keyboard selective (only shown to mentioned users).
keyboard.selected(isEnabled?: boolean): Keyboard
isEnabled
boolean
Whether to enable selective mode. Defaults to true.

oneTime

Makes the keyboard hide after a button is pressed.
keyboard.oneTime(isEnabled?: boolean): Keyboard
isEnabled
boolean
Whether to enable one-time mode. Defaults to true.
Example:
const keyboard = new Keyboard()
  .text('Yes').text('No')
  .oneTime()

resized

Makes the keyboard resize to fit its buttons.
keyboard.resized(isEnabled?: boolean): Keyboard
isEnabled
boolean
Whether to enable resizing. Defaults to true.

placeholder

Sets the input field placeholder text.
keyboard.placeholder(value: string): Keyboard
value
string
required
The placeholder text
Example:
const keyboard = new Keyboard()
  .text('Option 1').text('Option 2')
  .placeholder('Choose an option...')

Static Methods

Keyboard.text

Creates a text button without adding it to a keyboard.
Keyboard.text(text: string, options?: KeyboardButton.CommonButton['style'] | Omit<KeyboardButton.CommonButton, 'text'>): KeyboardButton.CommonButton

Keyboard.from

Creates a keyboard from a two-dimensional button array.
Keyboard.from(source: KeyboardButton[][] | Keyboard): Keyboard
source
KeyboardButton[][] | Keyboard
required
Button array or existing keyboard to copy
Example:
const data = [['A', 'B'], ['C', 'D']]
const keyboard = Keyboard.from(data)

// With button objects:
const button = Keyboard.text('Click me')
const keyboard = Keyboard.from([[button]])
All other button methods (requestUsers, requestChat, etc.) also have static equivalents.

Complete Example

import { Bot, Keyboard } from 'grammy'

const bot = new Bot('YOUR_BOT_TOKEN')

bot.command('start', async (ctx) => {
  const keyboard = new Keyboard()
    .text('👍 Like').text('👎 Dislike').row()
    .requestLocation('Share location').row()
    .requestContact('Share contact').row()
    .webApp('Open App', 'https://example.com')
    .resized()
    .oneTime()
  
  await ctx.reply('Choose an option:', {
    reply_markup: keyboard
  })
})

// Advanced example with styles
bot.command('menu', async (ctx) => {
  const keyboard = new Keyboard()
    .text('Create').success().row()
    .text('Edit').primary().text('Delete').danger().row()
    .text('Cancel')
    .resized()
    .persistent()
  
  await ctx.reply('Main menu:', {
    reply_markup: keyboard
  })
})

// Using static methods
bot.command('grid', async (ctx) => {
  const buttons = [
    ['1', '2', '3'],
    ['4', '5', '6'],
    ['7', '8', '9']
  ]
  const keyboard = Keyboard.from(buttons).resized()
  
  await ctx.reply('Select a number:', {
    reply_markup: keyboard
  })
})

bot.start()

See Also

Build docs developers (and LLMs) love