Telegram bot library for interactive panels
Keygram provides wrappers for Telegram’s callback queries, making it easier to create interactive panels.
In the near future, I plan to add media caching, a plugin system, and enhanced inline_query support.
Tested in Bun and Node ecosystems, JavaScript and TypeScript
- Functions “embedded” into buttons
When creating a keyboard with callbacks, they are stored in a global store and executed whenever thecallback_queryis processed. - Built-in security
By default, callback buttons have signatures that make it harder to forge arguments.
This feature can be disabled:new TelegramBot({ token, signCallbacks: false }) - Text editing
- Use a single method
ctx.edit()to edit both text and file captions. No more separatebot.editMessageTextorbot.editMessageCaptioncalls! - The adaptive method
ctx.respond()will either send a new message or edit the existing one (if triggered by a callback button)
- Use a single method
There are more features and they will be documented soon. For now, you can look at examples!
Install using your preferred package manager:
# With Bun
bun add keygram
# With npm
npm install keygram
# With yarn
yarn add keygramimport { TelegramBot, Panel } from "keygram"
const bot = new TelegramBot("YOUR_TOKEN")
/* Example: function is pre-defined */
const clicked = (ctx, amount = 0) => {
const btnText = "✨ Button clicked " + amount + " times"
const keyboard = Panel().Callback(btnText, clicked, amount + 1)
// Use ctx.edit() to edit the message, or ctx.reply() to send a new one
ctx.edit(`You clicked <b>the button!</b>`, keyboard)
}
const mainMenu = Panel().Callback("✨ Click me!", clicked)
.Row()
.Button("Dummy button") // No callback_data needed
bot.on('/start', ctx => ctx.reply(`Welcome, <b>${ctx.from.first_name}</b>!`, mainMenu))
bot.setParser('HTML')
bot.startPolling()Pagination functions can be asynchronous, but in this example it's not using that.
import { TelegramBot, Panel, Text, Pagination } from "keygram";
const bot = new TelegramBot("YOUR_TOKEN");
const data = [1, 2, 3, 4, 5, 6, 7].map(x => ({ number: Math.random() }))
const exampleText = (ctx, data, page) =>
`Your personal numbers PikiWedia\nYou're on page ${page+1}/${ctx.maxPage}!`
// If you want to display a slice (for example, 5 elements out of 100) then
// return an array like: [ data_slice_array, total_entries_amount ]
// If you return e.g 7 out of 7 elements, then just return an array of data:
const exampleData = (ctx, page) => data
const exampleKeys = (_, data, page) =>
Panel().Add(data.map(({ number }) => [ Text("Float " + number.toFixed(4)) ]))
const close = ctx => ctx.delete()
const closeKeys = ctx => Panel().Callback("Close panel", close)
const pages = new Pagination("numbers").Text(exampleText)
.Data(exampleData)
.Keys(exampleKeys)
.AfterKeys(closeKeys)
.PageSize(3)
bot.on('/start', ctx => ctx.open(pages));
bot.startPolling()- Editable panel with an image
- Form input
- Better pagination
- Showcase of handlers
- Primitive counter (above)
- Pagination: Add a ready-to-use class for an interactive panel with pages
- Scenes: Add a scene system for multi-step interactions
- Optimisations: Refactor the core with best practices in mind! XP
- Persistent Callbacks: Add PersistentCallback to restore functions on startup
- Cached Assets: Add classes like CachedImage for better media handling
- More helpers: Simplify common Telegram Bot API tasks