Как сделать клавиатуру в телеграм боте на Node JS

Ошибка 400 Bad Request при отправке сообщения с полем keyboard чаще всего возникает из-за некорректно сформированного JSON-объекта, где вместо массива объектов кнопок передана строка или нарушена вложенность структуры данных. Чтобы реализовать полноценное взаимодействие с пользователем, необходимо четко различать два типа интерфейсов: Inline-клавиатуру, которая встраивается в само сообщение и исчезает при нажатии, и Reply-клавиатуру, которая заменяет стандартную клавиатуру устройства до момента её отмены или замены.

Библиотека node-telegram-bot-api или telegraf позволяют создавать эти интерфейсы через программный код, однако синтаксис формирования кнопок имеет свои тонкости. Ошибки в именовании полей (например, использование text вместо callback_data для Inline-кнопок) приводят к тому, что бот просто игнорирует команду или выдает исключение в консоль. Правильная настройка callback-функций критически важна для обработки нажатий на кнопки без перезагрузки сообщения.

Выбор библиотеки и настройка окружения

Для реализации функционала клавиатур в среде Node.js разработчики чаще всего выбирают две основные библиотеки: telegraf и node-telegram-bot-api. Первая является более современной, поддерживает асинхронный стиль async/await и имеет богатую экосистему middleware, что упрощает обработку сложных сценариев с клавиатурами. Вторая библиотека имеет более простой API для новичков, но её активная разработка замедлилась в последние годы, и она может вызывать трудности при поддержке в новых версиях языка.

Перед началом работы необходимо инициализировать проект и установить зависимости через менеджер пакетов. Если вы выбираете telegraf, команда установки будет выглядеть следующим образом: npm install telegraf. Важно сразу создать файл конфигурации, где будет храниться ваш API Token, полученный у @BotFather, и не загружать его в публичный репозиторий. Безопасность токена — первый шаг к стабильной работе вашего бота с клавиатурами.

Создайте файл index.js и подключите библиотеку, инициализируя нового бота. В коде следует сразу определить обработчик команды /start, который будет первым местом, где пользователь увидит вашу клавиатуру. Это базовый сценарий, на котором строится вся дальнейшая логика взаимодействия с интерфейсом.

Создание Inline-клавиатуры через Telegraf

Inline-клавиатура является наиболее гибким инструментом для навигации внутри бота, так как кнопки располагаются прямо в теле сообщения и не перекрывают поле ввода текста. В библиотеке telegraf для этого используется класс InlueKeyboard, который позволяет добавлять кнопки с разными типами действия: переход по ссылке, вызов веб-приложения или отправка callback-данных на сервер.

Ключевое отличие Inline-кнопок от обычных заключается в том, что они не требуют нажатия клавиши Enter или отправки сообщения. При нажатии на кнопку на сервер отправляется объект callback_query, который нужно обработать отдельно. Для этого вам необходимо зарегистрировать обработчик событий типа action и сопоставить его с уникальным идентификатором кнопки, переданным в поле callback_data.

Пример кода создания такой клавиатуры выглядит лаконично и логично. Вы создаете экземпляр клавиатуры, добавляете ряды кнопок методом row() и в конце передаете объект в метод ctx.replyWithInlineKeyboard().

const { InlineKeyboard } = require('telegraf/inlineKeyboard');

const keyboard = new InlineKeyboard();

keyboard.text('Открыть сайт', 'https://google.com');

keyboard.text('Назад', 'back_action');

ctx.reply('Выберите действие', {

reply_markup: keyboard

});

Настройка Reply-клавиатуры для навигации

Reply-клавиатура (ReplyKeyboardMarkup) полностью заменяет стандартную клавиатуру устройства пользователя, что делает её идеальной для создания меню с фиксированными опциями, такими как "Каталог", "Контакты" или "Помощь". В отличие от Inline-версии, эти кнопки видны постоянно, пока бот не отправит команду на удаление клавиатуры. Это создает ощущение полноценного приложения, а не просто текстового чата.

Для реализации в telegraf используется класс Keyboard. Вы можете настроить параметры отображения: количество кнопок в строке через resize и количество колонок. Также важно задать свойство oneTime, если клавиатура должна исчезнуть после выбора одного пункта, что часто используется в сценариях авторизации или выбора пола. Resize параметр делает кнопки адаптивными, чтобы они не выглядели слишком мелкими на мобильных устройствах.

Обработка нажатий на Reply-кнопки происходит в общем обработчике текстовых сообщений. Поскольку кнопка отправляет именно текст, который на неё написан, вам нужно сравнивать входящее сообщение с ожидаемыми значениями. Это создает риск коллизий, если пользователь введет этот же текст вручную, но для простых меню этот метод работает отлично и стабильно.

☑️ Настройка Reply-клавиатуры

Выполнено: 0 / 4

Обработка нажатий и динамическое обновление

Самой сложной частью работы с клавиатурами является динамическое изменение их содержимого в зависимости от действий пользователя. Часто возникает необходимость обновить текущее сообщение, заменив одну клавиатуру на другую, не отсылая новое сообщение. Для этого используется метод editMessageReplyMarkup, который требует message_id и chat_id текущего сообщения.

Если вы используете Inline-клавиатуру, вы можете легко менять текст кнопок или добавлять новые ряды, просто вызвав метод редактирования сообщения. Это позволяет реализовать сложные сценарии, например, корзину товаров, где при нажатии "Купить" кнопка исчезает или меняет текст на "В корзине". Важно сохранять контекст, чтобы знать, какое именно сообщение нужно обновить.

В случае с Reply-клавиатурой обновление происходит через отправку нового текста с новым объектом reply_markup. Это может привести к дублированию сообщений, если не использовать метод ctx.editMessageText (работает только с Inline) или аккуратно управлять историей чата. Динамическая перерисовка клавиатуры без создания новых сообщений — ключевой фактор сохранения чистоты диалога.

Обработка ошибок при обновлении

Если вы пытаетесь обновить сообщение, которое уже было удалено или изменено пользователем, Telegram вернет ошибку 400 с кодом 'Message is not modified'. Рекомендуется обернуть вызов редактирования в блок try-catch и проверять наличие ошибок перед отправкой.

Таблица сравнения типов клавиатур

Понимание различий между типами клавиатур поможет выбрать правильный инструмент для конкретной задачи. Ниже приведена сравнительная таблица, демонстрирующая основные характеристики и ограничения каждого типа в контексте использования с Node.js.

Характеристика Inline-клавиатура Reply-клавиатура Кнопка-ссылка
Расположение Внутри сообщения Вместо системной клавиатуры Внутри Inline
Отправка данных Callback-запрос Текст сообщения Открытие URL
Длительность До обновления сообщения До удаления или замены До обновления сообщения
Ограничения по кнопкам До 800 символов в callback_data До 100 кнопок, 4 в ряд Любое количество ссылок
📊 Какой тип клавиатуры вы используете чаще всего?
Inline-клавиатура:Reply-клавиатура:Ссылки на сайты:Комбинированный подход

Типичные ошибки и способы их устранения

Разработчики часто сталкиваются с ошибкой 400 Bad Request при попытке отправить клавиатуру, содержащую слишком длинные данные в поле callback_data. Максимальная длина строки для этого поля составляет 64 символа. Если вы передаете туда JSON-объект или длинный ID, сервер Telegram отклонит запрос. Решение — использовать короткие идентификаторы (например, цифры) и загружать полные данные из базы данных при получении запроса.

Еще одна частая проблема — дублирование обработчиков. Если вы регистрируете обработчик действия ctx.action('buy') внутри цикла или функции, которая вызывается многократно, бот может начать дублировать ответы или работать некорректно. Всегда размещайте registration middleware на верхнем уровне приложения, чтобы гарантировать их однократную инициализацию при запуске.

⚠️ Внимание: Никогда не используйте пользовательский ввод напрямую в качестве callback_data без предварительной валидации и ограничения длины. Это может привести к переполнению буфера или уязвимостям, если злоумышленник подберет специальные символы.

Иногда кнопки не отображаются из-за неправильного формата JSON, особенно при ручном формировании объекта. Убедитесь, что структура валидна: массив массивов строк для Reply-клавиатуры и массив объектов для Inline. Использование готовых классов библиотек telegraf устраняет эту проблему, так как они автоматически сериализуют данные.

⚠️ Внимание: При использовании oneTimeKeyboard помните, что клавиатура исчезает сразу после нажатия любой кнопки. Если пользователю нужно выполнить последовательность действий, этот параметр может быть неуместен, и лучше использовать resizeKeyboard без oneTime.

Продвинутые сценарии использования

В современных ботах часто требуется создавать иерархические меню с возможностью возврата в прошлые этапы. Это реализуется через хранение состояния (state) в базе данных или сессиях. При нажатии на кнопку "Назад" бот считывает предыдущее состояние и генерирует соответствующую клавиатуру. Такой подход позволяет создавать сложные витрины товаров, каталоги услуг и формы обратной связи.

Также популярна практика использования Web App (мини-приложений) внутри Inline-кнопок. Вместо отправки текста или callback-данных, кнопка открывает браузерное окно прямо внутри Telegram. Это позволяет использовать полноценный HTML/CSS/JS интерфейс для выбора товаров или ввода данных, а затем передавать результат обратно в бота. Это идеальный вариант для сложных форм.

Для управления состояниями в telegraf часто используют middleware session, который сохраняет контекст между сообщениями. Это позволяет кнопкам вести себя умнее: например, кнопка "Купить" может быть доступна только тем пользователям, которые уже добавили товар в корзину. Логика проверки доступности кнопок должна быть инкапсулирована в отдельном сервисе.

FAQ: Частые вопросы по клавиатурам

Как удалить клавиатуру у пользователя?

Чтобы удалить Reply-клавиатуру, необходимо отправить новое сообщение с параметром reply_markup: { remove_keyboard: true }. Для Inline-клавиатуры можно отправить пустой объект reply_markup: {} через метод редактирования сообщения, что уберет кнопки, оставив текст.

Можно ли сделать кнопки разного цвета?

Стандартный Telegram API не поддерживает изменение цветов кнопок. Кнопки всегда имеют системный цвет (обычно серый или синий в зависимости от темы). Для кастомного дизайна необходимо использовать Web App, но это уже полноценное веб-приложение, а не нативная кнопка.

Как ограничить количество кнопок в строке?

Для Inline-клавиатуры количество кнопок в ряду не ограничено жестко, но есть лимит по общей ширине экрана. Для Reply-клавиатуры максимальное количество кнопок в строке — 4. Вы можете использовать метод row() для переноса на новую строку нужное число раз.

Почему callback_data не приходит на сервер?

Это может быть связано с тем, что кнопка была нажата, но сообщение было удалено или изменено до обработки запроса. Также проверьте, что вы используете правильный метод bot.on('callback_query'..) или bot.action('..'..) для перехвата событий.

Как передать данные в callback_data?

Лучше передавать короткие ID (например, 'product_id_123'). Длинные данные или JSON можно хранить в базе данных, а по ID подгружать информацию при получении callback-запроса. Прямая передача больших объемов данных в поле callback_data запрещена лимитами API.

Реализация клавиатур в Node.js ботах открывает широкие возможности для автоматизации и улучшения пользовательского опыта. Главное — внимательно следить за структурой данных, валидировать входные параметры и выбирать тип интерфейса, соответствующий задаче. Правильно настроенная клавиатура превращает текстового бота в удобное приложение для взаимодействия с пользователем.