Как сделать Telegram Mini App на React
Практика3 минРедакция Innovialabs
Коротко
Mini App на React — обычное веб-приложение по HTTPS, которое подключает скрипт telegram-web-app.js, берёт цвета из themeParams, управляет нативными MainButton и BackButton через window.Telegram.WebApp и открывается из бота.
Короткий ответ
Telegram Mini App — это веб-приложение, которое Telegram открывает внутри себя по кнопке бота. Технически это обычный React-проект, к которому подключён SDK telegram-web-app.js. Через объект window.Telegram.WebApp приложение получает:
- themeParams — цвета текущей темы пользователя;
- MainButton и BackButton — нативные кнопки Telegram;
- initData — подписанные данные о пользователе, которые нужно проверять на сервере.
Шаг 1. Проект и SDK
npm create vite@latest my-mini-app -- --template react-ts
cd my-mini-app
npm install
В index.html подключите SDK до вашего бандла:
<head>
<script src="https://telegram.org/js/telegram-web-app.js"></script>
</head>
Для TypeScript добавьте минимальное объявление или установите пакет с типами для Telegram Web Apps. Ниже используется короткая обёртка:
// src/tg.ts
export const tg = (window as any).Telegram?.WebApp;
В main.tsx сообщите Telegram, что приложение готово, и разверните его на всю высоту:
import { tg } from "./tg";
tg?.ready();
tg?.expand();
ready() убирает индикатор загрузки. Вызывайте его как можно раньше.
Шаг 2. Тема
SDK сам выставляет CSS-переменные вида --tg-theme-bg-color, --tg-theme-text-color, --tg-theme-button-color. Проще всего строить стили на них:
body {
background: var(--tg-theme-bg-color, #fff);
color: var(--tg-theme-text-color, #000);
}
.card {
background: var(--tg-theme-secondary-bg-color, #f2f2f2);
}
.hint {
color: var(--tg-theme-hint-color, #888);
}
Если цвета нужны в JS, они лежат в tg.themeParams, а светлая или тёмная схема — в tg.colorScheme. При смене темы приходит событие themeChanged: подпишитесь через tg.onEvent("themeChanged", handler). Запасные значения в var(..., #fff) нужны, чтобы страница выглядела нормально и в обычном браузере.
Шаг 3. MainButton
MainButton — большая кнопка внизу экрана, нативная для Telegram. Удобно обернуть её в хук:
import { useEffect } from "react";
import { tg } from "./tg";
export function useMainButton(text: string, onClick: () => void, visible = true) {
useEffect(() => {
const btn = tg?.MainButton;
if (!btn) return;
btn.setText(text);
btn.onClick(onClick);
visible ? btn.show() : btn.hide();
return () => {
btn.offClick(onClick);
btn.hide();
};
}, [text, onClick, visible]);
}
Главное здесь — offClick в очистке эффекта. Без него при каждом рендере добавляется новый обработчик, и одно нажатие вызывает несколько заказов. Для долгих операций есть btn.showProgress() и btn.hideProgress(), а btn.disable() блокирует повторные нажатия.
Шаг 4. BackButton и роутинг
BackButton появляется в шапке Mini App. Связывать её стоит с роутером, например react-router:
import { useEffect } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import { tg } from "./tg";
export function useBackButton() {
const navigate = useNavigate();
const { pathname } = useLocation();
useEffect(() => {
const back = tg?.BackButton;
if (!back) return;
const goBack = () => navigate(-1);
if (pathname === "/") back.hide();
else back.show();
back.onClick(goBack);
return () => back.offClick(goBack);
}, [pathname, navigate]);
}
На главном экране кнопка скрыта: там пользователь закрывает приложение системной кнопкой.
Шаг 5. Тестирование внутри Telegram
- HTTPS-адрес. Telegram открывает только HTTPS. Для разработки запустите
npm run devи пробросьте порт через туннель (ngrok, Cloudflare Tunnel и подобные). Если Vite блокирует чужой хост, добавьте его вserver.allowedHosts. - Привязка к боту. В @BotFather настройте Mini App или кнопку меню бота и укажите адрес туннеля. Другой вариант — inline-кнопка с полем
web_app. - Отладка. Проще всего начать с Telegram Web или Desktop: там доступны инструменты разработчика браузера. Для мобильных клиентов в документации Telegram описано, как включить отладку WebView.
- Тестовая среда. У Telegram есть отдельный тестовый сервер, чтобы не трогать продакшен-бота.
Частые ошибки
- Доверие к
initDataUnsafeна сервере. Это данные без проверки. Отправляйте на бэкенд строкуtg.initDataи проверяйте её подпись токеном бота. - Жёстко заданные цвета — в тёмной теме интерфейс становится нечитаемым.
- Обработчики MainButton без
offClick— повторные действия. - Нет проверки на запуск вне Telegram:
tgравенundefined, и приложение падает.