--- url: /commands/components.md description: >- Кнопки и меню выбора в пользовательских командах — стили, действия, component.id, листание страниц, select_menu, кнопки внутри текста. --- # Кнопки и меню выбора

Кнопки в пользовательских командах не только открывают ссылки — они запускают действия. «Подтвердить», «Следующая страница», «Получить роль», выбор варианта из меню — все это кнопки.

## Функция `button` { #button } ```template {% do button('PRIMARY', 'accept', 'Подтвердить', '✅', '59f7f318-17c9-45b8-be61-33c1f89d54ba') %} ``` Аргументы по порядку: | № | Аргумент | Что писать | |---|---|---| | 1 | Стиль | `PRIMARY` — синяя, `SUCCESS` — зеленая, `DANGER` — красная, `SECONDARY` — обычная, `LINK` — ссылка | | 2 | ID или ссылка | Для обычных кнопок — ID кнопки, который вы придумываете сами (`'accept'`). Для `LINK` — адрес `https://…` | | 3 | Надпись | Текст на кнопке. Можно `null`, если есть эмодзи | | 4 | Эмодзи | Необязательно. Встанет перед надписью | | 5 | Действие | UUID действия этой команды или `'self'` — текущее действие | | 6 | Неактивная | Необязательно. `true` — кнопка видна, но не нажимается | Какие бывают кнопки Кнопки, добавленные подряд, встают в один ряд. `{% do row() %}` начинает новый ряд. ::: info Где работают кнопки с действиями Кнопки, которые запускают действие, есть только в пользовательских командах. В приветствиях и других местах доступны кнопки-ссылки и «Скопировать» — см. [Кнопки под сообщением](/templates/beginners/buttons). ::: ## Какая кнопка нажата { #component-id } Когда кнопка запускает действие, в шаблоне появляется переменная `component`: | Свойство | Что в нем | |---|---| | `component.id` | ID нажатой кнопки — тот, что вы указали вторым аргументом | | `component.type` | `BUTTON` — нажата кнопка, `SELECTION_MENU` — выбран пункт меню | | `component.selectedOptions` | Выбранные пункты меню | Если действие запущено командой, а не кнопкой, `component.id` пустой. Так одно действие может вести себя по-разному: ```template {% if component.id == 'refresh' %}Обновлено!{% else %}Первый запуск{% endif %} ``` ## Кто может нажимать { #permissions } Нажать кнопку может любой, кто видит сообщение, но бот проверяет права: у нажавшего должен быть доступ к команде и к действию кнопки (если у действия [переопределены права](./actions/#settings)). Если прав нет, бот покажет всплывающее уведомление. Действие кнопки выполняется **от имени нажавшего**: в `member` будет он, а не тот, кто вызвал команду. ## Пример: подтверждение бана { #confirm } Три действия: «Спросить» (по умолчанию), «Бан» и «Отмена». **«Спросить»** — отправка сообщения: ```template {% set target = arguments.targetMember %} {% require target returning 'Укажите участника!' %} {% do parameters.store('memberId', target.id) %} {% do parameters.store('reason', arguments.after(2) ?: 'Без причины') %} ### Забанить {{ target }}? {{ quote(arguments.after(2) ?: 'Причина не указана') }} {% do button('DANGER', 'accept', 'Забанить', '⛔', '59f7f318-17c9-45b8-be61-33c1f89d54ba') %} {% do button('SECONDARY', 'cancel', 'Отмена', null, 'c18e2b11-2760-464b-b9f4-f04b7db349bc') %} ``` **«Бан»** — [встроенная команда](./actions/internal): ```template ban {{ parameters.memberId }} {{ parameters.reason }} ``` **«Отмена»** — отправка сообщения с флажком «Заменять сообщение с нажатой кнопкой»: ```template Бан отменен. ``` ### Забанить [Иван](#)? > спам ## Листание страниц { #pagination } Кнопки «⬅️» и «➡️» перезапускают то же действие (`'self'`), а номер страницы хранится в [параметрах](/templates/storage/parameters). Включите у действия флажок **«Заменять сообщение с нажатой кнопкой»**, чтобы страница менялась в том же сообщении. ```template {% set page = parameters.get('page') ?: 0 %} {% if component.id == 'next' %}{% set page += 1 %}{% elseif component.id == 'prev' and page > 0 %}{% set page -= 1 %}{% endif %} {% do parameters.store('page', page) %} {% set items = ['Броулбол', 'Захват кристаллов', 'Ограбление', 'Нокаут', 'Горячая зона', 'Награда за поимку', 'Осада'] %} {% set pageItems = items | slice(page * 3, 3) %} **Режимы** · страница {{ page + 1 }} {% for item in pageItems %} {{ page * 3 + loop.index }}. {{ item }} {% endfor %} {% do button('SECONDARY', 'prev', null, '⬅️', 'self', page == 0) %} {% do button('SECONDARY', 'next', null, '➡️', 'self', (page + 1) * 3 >= (items | length)) %} ``` **Режимы** · страница 1 1. Броулбол 2. Захват кристаллов 3. Ограбление Готовый пример с топом по данным из [индексов](/templates/storage/indexes) — в статье [Полезные примеры](/templates/examples#top). ## Меню выбора { #select-menu } В Telegram нет выпадающих списков, поэтому меню выбора бот рисует **кнопками-вариантами**. Участник нажимает вариант — запускается действие меню. ```template Какой режим тебе нравится? {% do select_menu('STRING', 'mode', 'Выбери режим', 'self') .addOption('Броулбол', 'brawlball', '⚽') .addOption('Захват кристаллов', 'gemgrab', '💎') .addOption('Одиночное ШД', 'showdown', '🌵') %} ``` Какой режим тебе нравится? Аргументы `select_menu`: тип меню, ID меню, подсказка, действие и (необязательно) неактивность. | Метод | Что делает | |---|---| | `.addOption(надпись, значение, эмодзи?, описание?)` | Добавить вариант. Описание в Telegram не показывается | | `.withDefaultOption(значение)` | Отметить вариант галочкой ✓ | | `.endMenu()` | Завершить меню, если оно строится внутри `createMessage()` | В действии меню выбранное значение лежит в `component.selectedOptions` — это список из одного элемента: ```template {% if component.type == 'SELECTION_MENU' %} {% set choice = component.selectedOptions | first %} Ты выбрал: {{ choice }} {% endif %} ``` | Тип меню | Что в вариантах | |---|---| | `STRING` | Ваши варианты из `addOption` | | `ROLE` | Роли бота | | `USER`, `CHANNEL`, `MENTIONABLE` | Не поддерживаются: Telegram не дает боту списки участников и каналов. Редактор покажет ошибку | ::: info Скоро: выбор нескольких вариантов Меню с выбором нескольких пунктов и кнопкой «Готово» (`withMinValues`, `withMaxValues`, `withRequiredRange`) появится позже. Сейчас выбирается один вариант. ::: ## Кнопки внутри текста { #inline } В rich-сообщениях кнопки можно поставить прямо между абзацами, а не только под сообщением: | Функция | Что делает | |---|---| | `button_row([кнопки], выравнивание?)` | Ряд из 1–8 кнопок между блоками текста. Выравнивание: `'left'`, `'center'`, `'right'` | | `inline_button(…)` | Одна кнопка прямо в строке текста. Аргументы — как у `button` | ```template ## Выбери сторону {{ button_row([ button('PRIMARY', 'red', 'Красные', '🔴', 'self'), button('PRIMARY', 'blue', 'Синие', '🔵', 'self') ], 'center') }} Голосование закончится в полночь. ``` В режиме Text такие кнопки переедут в обычную клавиатуру под сообщением. ## Кнопка «Скопировать» { #copy } ```template {% do copy_button('Скопировать мой ID', member.id) %} ``` Кнопка копирует текст в буфер обмена и не запускает действие. ## Сколько живут кнопки { #lifetime } * Кнопка работает 180 дней с последнего нажатия. Если нажать старую кнопку, бот ответит «Кнопка устарела». * Один участник может нажимать кнопки не чаще 20 раз за 10 секунд — иначе бот ответит «Слишком часто». * Под одним сообщением — не больше 25 кнопок.