---
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 кнопок.