Token导航 LogoToken导航TokenDH.com
开发需要联网github未标认证来源可访问许可证需确认审计提醒

telegram-mini-app-skillTelegram mini 应用技能

Agent Skill

telegram-mini-app-skill 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

294

周安装

12

GitHub Stars

3

下载量

94
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:telegram-mini-app-skill(Telegram mini 应用技能)
来源仓库:https://github.com/rithprohos/telegram-mini-app-skills
仓库路径:skills/telegram-mini-app-skill
安装命令:
npx skills add https://github.com/rithprohos/telegram-mini-app-skills --skill telegram-mini-app-skill
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/rithprohos/telegram-mini-app-skills --skill telegram-mini-app-skill

简介

telegram-mini-app-skill 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息。

  • 适合在 Codex、Claude、Cursor、Gemini CLI 中围绕仓库状态、代码变更或协作事项进行整理。
  • 通过 npx skills add 命令从指定 GitHub 仓库安装并使用。
  • 安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。
  • 可结合来源仓库和原始 README 进一步核验具体用法。

SKILL.md

Telegram Mini App Development Guide

Official Reference: core.telegram.org/bots/webapps

This skill is a framework-agnostic guide for building Telegram Mini Apps. Whether you use React, Vue, Svelte, Angular, Solid, or vanilla HTML/JS — this guide covers the universal SDK concepts, theming system, and best practices.


Table of Contents

  1. What is a Telegram Mini App?
  2. Loading the SDK
  3. The WebApp Object
  4. Initialization Lifecycle
  5. Theming & CSS Variables
  6. Navigation Components
  7. Bottom Buttons (MainButton & SecondaryButton)
  8. Haptic Feedback
  9. Popups & Alerts
  10. Data Validation & Security
  11. Storage APIs
  12. Full-Screen Mode
  13. Safe Areas
  14. Available Events
  15. Framework Integration Recipes
  16. Design Guidelines
  17. Testing & Debugging
  18. Common Pitfalls

1. What is a Telegram Mini App?

Telegram Mini Apps are web applications (HTML, CSS, JavaScript) that run inside the Telegram messenger. They can be launched from:

  • Bot menus — via BotFather's menu button configuration
  • Inline buttonsweb_app type in bot messages
  • Attachment menu — bot added to the attachment menu
  • Direct linkst.me/botname/appname
  • Keyboard buttonsweb_app type keyboard buttons
  • Home screen shortcuts — users can add Mini Apps to their home screen

Key characteristics:

  • Must be served over HTTPS
  • Run in a WebView on all platforms (iOS, Android, Desktop, Web)
  • Can access Telegram user data, theme, and native UI components
  • Associated with a bot created via @BotFather

2. Loading the SDK

Option A: Script Tag (All Frameworks)

Place this in your <head> before any other scripts:

<script src="https://telegram.org/js/telegram-web-app.js"></script>

This creates the window.Telegram.WebApp object and automatically injects CSS variables for theming.

Option B: npm Packages

For modern JavaScript projects with bundlers:

# Official community SDK (TypeScript-first, tree-shakeable)
npm install @telegram-apps/sdk

# Alternative lightweight wrapper
npm install @twa-dev/sdk

Framework-Specific Loading

FrameworkHow to Load
Vanilla HTML<script> tag in <head>
React / Next.js<Script src="..." strategy="beforeInteractive" /> via next/script, or <script> in index.html
Vue / Nuxt<script> in index.html, or Nuxt plugin with useHead()
Svelte / SvelteKit<svelte:head> tag or app.html
AngularAdd to angular.json scripts array or index.html

3. The WebApp Object

Once the SDK is loaded, the main API is available at:

const tg = window.Telegram.WebApp;

Key Properties

PropertyTypeDescription
initDatastringRaw init data string for backend validation
initDataUnsafeobjectParsed init data (user, chat, etc.) — not validated, do not trust client-side
versionstringSDK version (e.g., "8.0")
platformstringPlatform identifier ("android", "ios", "tdesktop", "web", "unknown")
colorSchemestring"light" or "dark"
themeParamsobjectCurrent theme colors as key-value pairs
isExpandedbooleanWhether the Mini App is expanded to full height
viewportHeightnumberCurrent viewport height in pixels
viewportStableHeightnumberStable viewport height (doesn't change with keyboard)
headerColorstringCurrent header color (#RRGGBB)
backgroundColorstringCurrent background color (#RRGGBB)
bottomBarColorstringCurrent bottom bar color (#RRGGBB)
isFullscreenbooleanWhether full-screen mode is active

Key Sub-Objects

Sub-ObjectDescription
BackButtonControls the back button in the header
MainButtonControls the primary bottom button
SecondaryButtonControls the secondary bottom button
SettingsButtonControls the settings item in the context menu
HapticFeedbackControls haptic/vibration feedback
CloudStorageCloud key-value storage (up to 1024 items, synced across devices)
DeviceStoragePersistent local storage (up to 5 MB, device-only)
SecureStorageEncrypted storage using OS keychain/keystore (up to 10 items)
BiometricManagerBiometric authentication
AccelerometerAccelerometer sensor data
GyroscopeGyroscope sensor data
DeviceOrientationDevice orientation data
LocationManagerLocation access

4. Initialization Lifecycle

Every Mini App must call tg.ready() to signal to Telegram that the app is ready to be displayed.

Universal Pattern (Any Framework)

// 1. Get the WebApp instance
const tg = window.Telegram.WebApp;

// 2. Signal ready
tg.ready();

// 3. Expand to full height (recommended)
tg.expand();

// 4. Access user data
const user = tg.initDataUnsafe?.user;
console.log(user?.first_name, user?.username);

Why ready() Matters

  • Telegram shows a loading placeholder until ready() is called
  • Call it as early as possible after your app's initial UI has rendered
  • Don't call it before your app has something meaningful to display

5. Theming & CSS Variables

The Golden Rule

NEVER hardcode colors. Use the CSS variables that Telegram's SDK injects automatically. This ensures your app looks native in Light mode, Dark mode, and across all platforms.

Available CSS Variables

The SDK automatically sets these CSS variables on the <html> element:

CSS VariableJS Property (themeParams.X)Description
--tg-theme-bg-colorbg_colorMain background
--tg-theme-text-colortext_colorPrimary text
--tg-theme-hint-colorhint_colorSecondary/hint text
--tg-theme-link-colorlink_colorLinks
--tg-theme-button-colorbutton_colorPrimary button background
--tg-theme-button-text-colorbutton_text_colorButton text
--tg-theme-secondary-bg-colorsecondary_bg_colorSecondary background (cards, sections)
--tg-theme-header-bg-colorheader_bg_colorHeader background
--tg-theme-bottom-bar-bg-colorbottom_bar_bg_colorBottom bar background
--tg-theme-accent-text-coloraccent_text_colorAccent text
--tg-theme-section-bg-colorsection_bg_colorSection/card background
--tg-theme-section-header-text-colorsection_header_text_colorSection header text
--tg-theme-section-separator-colorsection_separator_colorSeparator lines
--tg-theme-subtitle-text-colorsubtitle_text_colorSubtitle text
--tg-theme-destructive-text-colordestructive_text_colorDestructive/danger text

Additional CSS Variables

CSS VariableDescription
--tg-color-scheme"light" or "dark"
--tg-viewport-heightCurrent viewport height
--tg-viewport-stable-heightStable viewport height
--tg-safe-area-inset-topSystem safe area (top)
--tg-safe-area-inset-bottomSystem safe area (bottom)
--tg-safe-area-inset-leftSystem safe area (left)
--tg-safe-area-inset-rightSystem safe area (right)
--tg-content-safe-area-inset-topTelegram UI safe area (top)
--tg-content-safe-area-inset-bottomTelegram UI safe area (bottom)
--tg-content-safe-area-inset-leftTelegram UI safe area (left)
--tg-content-safe-area-inset-rightTelegram UI safe area (right)

Usage Examples

✅ CORRECT — Using CSS Variables

/* CSS */
body {
  background-color: var(--tg-theme-bg-color, #ffffff);
  color: var(--tg-theme-text-color, #000000);
}

.card {
  background-color: var(--tg-theme-section-bg-color, #f5f5f5);
  border: 1px solid var(--tg-theme-section-separator-color, #e0e0e0);
}

.button-primary {
  background-color: var(--tg-theme-button-color, #3b82f6);
  color: var(--tg-theme-button-text-color, #ffffff);
}

.hint-text {
  color: var(--tg-theme-hint-color, #999999);
}
Always provide fallback values (the second argument in var()) so your app works outside of Telegram during development.

❌ WRONG — Hardcoded Colors

/* NEVER do this */
body {
  background-color: #ffffff;
  color: #000000;
}
.dark body {
  background-color: #1a1a1a;
  color: #ffffff;
}

Creating a Shorthand Variable System (Recommended)

For convenience, map Telegram's verbose variables to shorter names in your global CSS:

:root {
  --bg: var(--tg-theme-bg-color, #ffffff);
  --fg: var(--tg-theme-text-color, #171717);
  --btn: var(--tg-theme-button-color, #3b82f6);
  --btn-text: var(--tg-theme-button-text-color, #ffffff);
  --hint: var(--tg-theme-hint-color, #a1a1aa);
  --link: var(--tg-theme-link-color, #007aff);
  --secondary-bg: var(--tg-theme-secondary-bg-color, #efeff4);
  --section-bg: var(--tg-theme-section-bg-color, #ffffff);
  --section-header: var(--tg-theme-section-header-text-color, #6d6d72);
  --subtitle: var(--tg-theme-subtitle-text-color, #8e8e93);
  --destructive: var(--tg-theme-destructive-text-color, #ff3b30);
  --accent: var(--tg-theme-accent-text-color, #007aff);
  --separator: var(--tg-theme-section-separator-color, #c8c7cc);
}

Listening to Theme Changes

tg.onEvent("themeChanged", () => {
  // Theme params have been updated
  // CSS variables are auto-updated by the SDK
  // If using JS theming, re-read tg.themeParams
  console.log("New color scheme:", tg.colorScheme);
});

6. Navigation Components

BackButton

Controls the native back button in the Telegram header. Use this instead of building your own back button.

// Show the back button
tg.BackButton.show();

// Handle clicks
tg.BackButton.onClick(() => {
  // Navigate back in your app's routing
  history.back(); // or your router's back method
});

// Hide when no longer needed
tg.BackButton.hide();

// Remove a specific handler
tg.BackButton.offClick(handler);

SettingsButton

Adds a "Settings" option to the Mini App's context menu (three-dot menu).

tg.SettingsButton.show();
tg.SettingsButton.onClick(() => {
  // Navigate to settings page
});

7. Bottom Buttons

Telegram provides two bottom buttons: MainButton (primary) and SecondaryButton (secondary). They appear fixed at the bottom of the Mini App.

MainButton

const btn = tg.MainButton;

// Configure and show
btn.setText("SUBMIT ORDER");
btn.show();

// Or use setParams for multiple properties at once
btn.setParams({
  text: "SUBMIT ORDER",
  color: tg.themeParams.button_color,
  text_color: tg.themeParams.button_text_color,
  is_active: true,
  is_visible: true,
  has_shine_effect: false,
});

// Handle click
btn.onClick(() => {
  // Perform the action
});

// Show loading state
btn.showProgress(true); // true = leave button active
btn.disable(); // prevent double-clicks

// Reset after completion
btn.hideProgress();
btn.enable();
btn.hide();

SecondaryButton

Works identically to MainButton:

tg.SecondaryButton.setParams({
  text: "CANCEL",
  is_visible: true,
});

tg.SecondaryButton.onClick(() => {
  // Handle secondary action
});

BottomButton Properties

Property / MethodDescription
.textButton text
.colorBackground color
.textColorText color
.isVisibleWhether the button is shown
.isActiveWhether the button is clickable
.isProgressVisibleWhether the loading spinner is shown
.setText(text)Update button text
.show() / .hide()Toggle visibility
.enable() / .disable()Toggle clickability
.showProgress(leaveActive)Show spinner
.hideProgress()Hide spinner
.setParams(params)Set multiple properties at once
.onClick(cb)Register click handler
.offClick(cb)Remove click handler

Important: Handler Cleanup

Always remove click handlers when they're no longer relevant (e.g., on component unmount or page navigation). Failure to do so can cause ghost handlers.


8. Haptic Feedback

Trigger native haptic vibrations for tactile feedback:

const haptic = tg.HapticFeedback;

// Impact feedback — for button presses, interactions
haptic.impactOccurred("light"); // light tap
haptic.impactOccurred("medium"); // medium tap
haptic.impactOccurred("heavy"); // strong tap
haptic.impactOccurred("rigid"); // rigid tap
haptic.impactOccurred("soft"); // soft tap

// Notification feedback — for results/outcomes
haptic.notificationOccurred("success"); // operation succeeded
haptic.notificationOccurred("error"); // operation failed
haptic.notificationOccurred("warning"); // caution

// Selection feedback — for selection changes
haptic.selectionChanged(); // e.g., picker/slider changes

When to Use

ScenarioType
Button tapimpactOccurred("light")
Form submit successnotificationOccurred("success")
Error responsenotificationOccurred("error")
Toggling a switchimpactOccurred("medium")
Slider/picker value changeselectionChanged()
Deleting an itemimpactOccurred("heavy")
Clear/reset actionimpactOccurred("light")

9. Popups & Alerts

Use native Telegram dialogs instead of browser alert() / confirm():

// Simple alert
tg.showAlert("File saved successfully!", () => {
  // Callback after user dismisses
});

// Confirmation dialog
tg.showConfirm("Are you sure you want to delete this?", (confirmed) => {
  if (confirmed) {
    // User tapped "OK"
  }
});

// Custom popup with buttons
tg.showPopup(
  {
    title: "Choose an option", // optional
    message: "What would you like to do?",
    buttons: [
      { id: "save", type: "default", text: "Save" },
      { id: "delete", type: "destructive", text: "Delete" },
      { id: "cancel", type: "cancel" }, // text is auto-set
    ],
  },
  (buttonId) => {
    switch (buttonId) {
      case "save":
        /* ... */ break;
      case "delete":
        /* ... */ break;
      case "cancel":
        /* ... */ break;
    }
  },
);

Popup Button Types

TypeBehavior
"default"Regular button
"ok""OK" text, closes popup
"close""Close" text, closes popup
"cancel""Cancel" text, closes popup
"destructive"Red/destructive styled button

10. Data Validation & Security

Client-Side Data

tg.initDataUnsafe gives you parsed user data, but it can be spoofed. Always validate on your backend.

// Client: send initData to your backend
const response = await fetch("/api/your-endpoint", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Telegram-Init-Data": tg.initData, // raw string for validation
  },
  body: JSON.stringify({
    /* your payload */
  }),
});

Server-Side Validation (HMAC-SHA256)

The backend must validate initData using the bot's token:

1. Parse initData as query string
2. Extract `hash` parameter, keep remaining fields
3. Sort remaining fields alphabetically
4. Create data_check_string = sorted fields joined with '\n' in "key=value" format
5. secret_key = HMAC_SHA256(bot_token, "WebAppData")
6. Compare: HMAC_SHA256(data_check_string, secret_key) == hash
7. Check auth_date for freshness

Pseudocode:

data_check_string = "auth_date=<auth_date>\nquery_id=<query_id>\nuser=<user>"
secret_key = HMAC_SHA256(<bot_token>, "WebAppData")
if hex(HMAC_SHA256(data_check_string, secret_key)) == hash:
    # Data is genuine and from Telegram

Third-Party Validation (Ed25519 Signatures)

For sharing data with third parties (who don't have your bot token), use the signature field with Telegram's public keys:

  • Production: e7bf03a2fa4602af4580703d88dda5bb59f32ed8b02a56c187fe7d34caed242d
  • Test env: 40055058a4ee38156a06562e52eece92a771bcd8346a8c4615cb7376eddf72ec

11. Storage APIs

CloudStorage (Synced Across Devices)

Up to 1024 key-value pairs, 4096 bytes per value, synced via Telegram's servers:

tg.CloudStorage.setItem("theme_pref", "dark", (err, success) => {});
tg.CloudStorage.getItem("theme_pref", (err, value) => {});
tg.CloudStorage.getItems(["key1", "key2"], (err, values) => {});
tg.CloudStorage.removeItem("theme_pref", (err, success) => {});
tg.CloudStorage.getKeys((err, keys) => {});

DeviceStorage (Local Only, Bot API 9.0+)

Up to 5 MB, persists on device, similar to localStorage:

tg.DeviceStorage.setItem("draft", longText);
tg.DeviceStorage.getItem("draft");

SecureStorage (Encrypted, Bot API 9.0+)

Up to 10 items, uses OS Keychain (iOS) / Keystore (Android):

tg.SecureStorage.setItem("auth_token", token);
tg.SecureStorage.getItem("auth_token");

12. Full-Screen Mode

Available since Bot API 8.0 (November 2024). Allows the Mini App to use the entire screen:

// Enter full-screen
tg.requestFullscreen();

// Exit full-screen
tg.exitFullscreen();

// Check status
console.log(tg.isFullscreen);

// Listen for changes
tg.onEvent("fullscreenChanged", () => {
  console.log("Fullscreen:", tg.isFullscreen);
});

tg.onEvent("fullscreenFailed", (event) => {
  console.log("Fullscreen failed:", event.error);
});
Important: When in full-screen mode, you must handle safe areas to avoid content overlapping with system UI elements (notch, status bar, etc.).

13. Safe Areas

Two types of safe areas to handle, especially critical in full-screen mode:

System Safe Area (notch, status bar, home indicator)

.content {
  padding-top: var(--tg-safe-area-inset-top, 0px);
  padding-bottom: var(--tg-safe-area-inset-bottom, 0px);
  padding-left: var(--tg-safe-area-inset-left, 0px);
  padding-right: var(--tg-safe-area-inset-right, 0px);
}

Content Safe Area (Telegram's own header, bottom bar)

It is highly recommended in frameworks like React/Next.js to avoid applying these to the raw document body, as Telegram's Webview injection can cause 100vw or scaling constraints to clip or shrink off-screen horizontally.

Instead, the most bulletproof approach across all Webview versions involves a hybrid Javascript-to-CSS fallback. Combining contentSafeAreaInset.top (Telegram UI) and safeAreaInset.top (Mobile Device Notches) prevents overlap completely:

1. Calculate and combine the padding natively in your Telegram Initialization loop:

// Add base safeArea (device notches) + contentSafe (Telegram header ui) together
// Apply a hard fallback (e.g., 48px) just in case Telegram fails to inject variables entirely
const top = Math.max(
  48,
  (tg.contentSafeAreaInset?.top || 0) + (tg.safeAreaInset?.top || 0),
);
const bottom = Math.max(
  32,
  (tg.contentSafeAreaInset?.bottom || 0) + (tg.safeAreaInset?.bottom || 0),
);

// Explicitly inject safe bounds into your root HTML variables
document.documentElement.style.setProperty("--safe-top", `${top}px`);
document.documentElement.style.setProperty("--safe-bottom", `${bottom}px`);

2. In your CSS (like globals.css or Tailwind config), reference the injected variables:

:root {
  /* You can optionally add env() fallbacks here if you want native browser backup */
  --safe-top: env(safe-area-inset-top, 48px);
  --safe-bottom: env(safe-area-inset-bottom, 32px);
}

3. Finally, in your React individual Page wrappers padding:

<main
  style={{
    // Add your desired extra padding (e.g., 1rem) to the base safe area boundary mathematically
    paddingTop: "calc(1rem + var(--safe-top))",
    paddingBottom: "calc(2rem + var(--safe-bottom))",
  }}
>
  {/* Content goes here safely below the Close/Settings notch */}
</main>

Listening for Safe Area Changes

tg.onEvent("safeAreaChanged", () => {
  // System safe area changed (e.g., orientation change)
});

tg.onEvent("contentSafeAreaChanged", () => {
  // Telegram UI safe area changed
});

14. Available Events

Register handlers with tg.onEvent(eventType, handler) and remove with tg.offEvent(eventType, handler):

EventTrigger
activatedMini App becomes active/visible
deactivatedMini App becomes inactive/hidden
themeChangedUser changed Telegram theme
viewportChangedViewport height changed (keyboard, expand)
safeAreaChangedSystem safe area insets changed
contentSafeAreaChangedTelegram content safe area changed
mainButtonClickedMain button was pressed
secondaryButtonClickedSecondary button was pressed
backButtonClickedBack button was pressed
settingsButtonClickedSettings button was pressed
invoiceClosedPayment invoice was closed
popupClosedPopup was closed
qrTextReceivedQR code was scanned
clipboardTextReceivedClipboard text was received
writeAccessRequestedWrite access permission result
contactRequestedContact sharing result
fullscreenChangedFull-screen state changed
fullscreenFailedFull-screen request failed
homeScreenAddedApp was added to home screen
homeScreenCheckedHome screen status checked
biometricManagerUpdatedBiometric manager state changed
biometricAuthRequestedBiometric auth result
shareMessageSentShare message was sent
shareMessageFailedShare message failed
emojiStatusSetEmoji status was set
emojiStatusFailedEmoji status setting failed
fileDownloadRequestedFile download request result

15. Framework Integration Recipes

Vanilla JavaScript

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script src="https://telegram.org/js/telegram-web-app.js"></script>
    <style>
      body {
        margin: 0;
        font-family: -apple-system, BlinkMacSystemFont, sans-serif;
        background: var(--tg-theme-bg-color, #fff);
        color: var(--tg-theme-text-color, #000);
      }
      .card {
        background: var(--tg-theme-section-bg-color, #f5f5f5);
        border-radius: 14px;
        padding: 16px;
        margin: 16px;
      }
      .hint {
        color: var(--tg-theme-hint-color, #999);
        font-size: 13px;
      }
    </style>
  </head>
  <body>
    <div class="card">
      <h1>Hello, <span id="username">User</span>!</h1>
      <p class="hint">Welcome to the Mini App</p>
    </div>
    <script>
      const tg = window.Telegram.WebApp;
      tg.ready();
      tg.expand();

      const user = tg.initDataUnsafe?.user;
      if (user) {
        document.getElementById("username").textContent = user.first_name;
      }

      tg.MainButton.setText("DONE");
      tg.MainButton.show();
      tg.MainButton.onClick(() => {
        tg.HapticFeedback.notificationOccurred("success");
        tg.close();
      });
    </script>
  </body>
</html>

React / Next.js

// hooks/useTelegram.ts — Reusable hook
import { useEffect, useState, useCallback } from "react";

export function useTelegram() {
  const [tg, setTg] = useState<TelegramWebApp | null>(null);
  const [user, setUser] = useState<TelegramUser | null>(null);

  useEffect(() => {
    if (typeof window !== "undefined" && window.Telegram?.WebApp) {
      const webapp = window.Telegram.WebApp;
      webapp.ready();
      webapp.expand();
      setTg(webapp);
      setUser(webapp.initDataUnsafe?.user || null);
    }
  }, []);

  const showMainButton = useCallback(
    (text: string, onClick: () => void) => {
      if (!tg) return;
      tg.MainButton.setText(text);
      tg.MainButton.show();
      tg.MainButton.onClick(onClick);
      return () => tg.MainButton.offClick(onClick);
    },
    [tg],
  );

  const showBackButton = useCallback(
    (onClick: () => void) => {
      if (!tg) return;
      tg.BackButton.show();
      tg.BackButton.onClick(onClick);
      return () => {
        tg.BackButton.offClick(onClick);
        tg.BackButton.hide();
      };
    },
    [tg],
  );

  return { tg, user, showMainButton, showBackButton };
}
// pages/MyPage.tsx
"use client";
import { useEffect } from "react";
import { useTelegram } from "@/hooks/useTelegram";

export default function MyPage() {
  const { tg, user, showBackButton } = useTelegram();

  useEffect(() => {
    return showBackButton?.(() => window.history.back());
  }, [showBackButton]);

  return (
    <main style={{ background: "var(--tg-theme-secondary-bg-color)" }}>
      <h1 style={{ color: "var(--tg-theme-text-color)" }}>
        Hello, {user?.first_name}!
      </h1>
    </main>
  );
}

Next.js Layout Setup

// app/layout.tsx
import Script from "next/script";

export default function RootLayout({ children }) {
  return (
    <html lang="en" suppressHydrationWarning>
      <body>
        <Script
          src="https://telegram.org/js/telegram-web-app.js"
          strategy="beforeInteractive"
        />
        {children}
      </body>
    </html>
  );
}
suppressHydrationWarning is required because Telegram's script injects style attributes into the DOM during SSR/hydration.

Vue 3 / Nuxt

<!-- composables/useTelegram.ts -->
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from "vue";

const tg = ref<any>(null);
const user = ref<any>(null);

export function useTelegram() {
  onMounted(() => {
    if (window.Telegram?.WebApp) {
      tg.value = window.Telegram.WebApp;
      tg.value.ready();
      tg.value.expand();
      user.value = tg.value.initDataUnsafe?.user || null;
    }
  });

  function showBackButton(onClick: () => void) {
    tg.value?.BackButton.show();
    tg.value?.BackButton.onClick(onClick);
    onUnmounted(() => {
      tg.value?.BackButton.offClick(onClick);
      tg.value?.BackButton.hide();
    });
  }

  return { tg, user, showBackButton };
}
</script>
<!-- pages/MyPage.vue -->
<template>
  <main :style="{ background: 'var(--tg-theme-secondary-bg-color)' }">
    <h1 :style="{ color: 'var(--tg-theme-text-color)' }">
      Hello, {{ user?.first_name }}!
    </h1>
  </main>
</template>

<script setup lang="ts">
import { useTelegram } from "@/composables/useTelegram";
import { useRouter } from "vue-router";

const { user, showBackButton } = useTelegram();
const router = useRouter();

showBackButton(() => router.back());
</script>

Svelte / SvelteKit

<!-- lib/telegram.ts -->
<script context="module" lang="ts">
  export function getTelegram() {
    if (typeof window !== 'undefined' && window.Telegram?.WebApp) {
      return window.Telegram.WebApp;
    }
    return null;
  }
</script>
<!-- routes/+page.svelte -->
<script lang="ts">
  import { onMount, onDestroy } from 'svelte';
  import { getTelegram } from '$lib/telegram';

  let user: any = null;

  onMount(() => {
    const tg = getTelegram();
    if (tg) {
      tg.ready();
      tg.expand();
      user = tg.initDataUnsafe?.user;

      tg.BackButton.show();
      tg.BackButton.onClick(() => history.back());
    }
  });

  onDestroy(() => {
    const tg = getTelegram();
    tg?.BackButton.hide();
  });
</script>

<main style="background: var(--tg-theme-secondary-bg-color); color: var(--tg-theme-text-color);">
  <h1>Hello, {user?.first_name ?? 'User'}!</h1>
</main>

SvelteKit Layout

<!-- src/app.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://telegram.org/js/telegram-web-app.js"></script>
    %sveltekit.head%
  </head>
  <body>
    %sveltekit.body%
  </body>
</html>

16. Design Guidelines

Telegram's official design principles for Mini Apps:

Core Principles

  1. Mobile-First: All elements must be responsive and optimized for mobile viewports
  2. Native Feel: Mimic the style and behavior of existing Telegram UI components
  3. Smooth Animations: Target 60fps for all animations
  4. Accessibility: All inputs and images should have labels
  5. Theme Adaptive: Use Telegram CSS variables for all colors
  6. Safe Area Aware: Respect safe areas, especially in full-screen mode
  7. Performance Conscious: On Android, check User-Agent for device performance class and reduce animations on low-end devices

Recommended UI Patterns

ElementRecommended Style
Page backgroundvar(--tg-theme-secondary-bg-color)
Cards / Sectionsvar(--tg-theme-section-bg-color) with border-radius: 14px
Section labelsUppercase, small font, var(--tg-theme-section-header-text-color)
Hint textSmaller font, var(--tg-theme-hint-color)
Separators1px line with var(--tg-theme-section-separator-color)
Input font size≥ 16px (prevents iOS auto-zoom on focus)
ButtonUse MainButton for primary actions, or custom with var(--tg-theme-button-color)
Destructive actionsvar(--tg-theme-destructive-text-color)
Bottom paddingAdd enough padding to avoid overlap with MainButton (~80px)

17. Testing & Debugging

Development Environment

  1. Run your dev server on localhost
  2. Expose via HTTPS tunnel: ngrok http 3000 (or Cloudflare Tunnel, localtunnel, etc.)
  3. Configure BotFather:

- Create/select your bot - Set the Web App URL via /setmenubutton or /newapp

  1. Open in Telegram and test

Debugging Tips

PlatformMethod
AndroidEnable WebView debugging in Android Developer Settings → chrome://inspect
iOSSafari → Develop → your device → your WebView
DesktopRight-click inside Mini App → "Inspect Element" (on some builds)
Telegram WebRegular browser DevTools

Testing Outside Telegram

Wrap all tg calls with a safety check. Provide fallback UI for development:

const tg = window.Telegram?.WebApp;
const isInTelegram = !!tg?.initData;

if (isInTelegram) {
  tg.ready();
  tg.MainButton.show();
} else {
  // Show a regular HTML button instead for local testing
  console.log("Running outside Telegram — showing fallback UI");
}

18. Common Pitfalls

PitfallSolution
Colors look wrong in TelegramUse --tg-theme-* CSS variables, never hardcode
App stuck on loading spinnerCall tg.ready() after initial render
MainButton not respondingAlways offClick(handler) before registering new handler
iOS zooms in on input focusSet input font-size to ≥ 16px
SSR hydration errors (Next.js, Nuxt)Add suppressHydrationWarning to <html> tag
initData is emptyApp was launched via keyboard button (expected) — handle gracefully
API calls return 403Validate initData correctly on server; check auth_date freshness
Stale state in button handlersUse refs (React) or reactive getters (Vue) — handlers capture closure variables
Content hidden behind MainButtonAdd bottom padding (~80–100px) to main content
Safe area content overlap in fullscreenUse --tg-safe-area-inset-* and --tg-content-safe-area-inset-* CSS variables
window.Telegram is undefinedSDK script not loaded yet — ensure it loads before your app code
Double-click on MainButtonDisable button and show progress immediately on click
Theme not updating dynamicallyListen to themeChanged event; CSS variables update automatically
Clipboard API not workingUse tg.readTextFromClipboard(), not the browser Clipboard API
File download not working on webInclude Content-Disposition and Access-Control-Allow-Origin: https://web.telegram.org response headers

Quick Reference: Useful Methods

const tg = window.Telegram.WebApp;

// Basics
tg.ready(); // Signal app is ready
tg.expand(); // Expand to full height
tg.close(); // Close the Mini App

// User data
tg.initData; // Raw string for server validation
tg.initDataUnsafe.user; // User object (not validated!)

// Navigation
tg.openLink(url); // Open URL in browser
tg.openLink(url, { try_instant_view: true }); // Try Instant View
tg.openTelegramLink(url); // Open telegram link (resolves inside Telegram)

// Sharing
tg.switchInlineQuery(query, ["users", "groups"]); // Switch to inline mode
tg.shareToStory(mediaUrl, params); // Share to Stories

// Clipboard
tg.readTextFromClipboard((text) => {}); // Read clipboard

// QR Code
tg.showScanQrPopup({ text: "Scan QR" }, (data) => {
  // Handle QR data
  return true; // return true to close popup
});
tg.closeScanQrPopup();

// Payments
tg.openInvoice(invoiceUrl, (status) => {
  // status: "paid", "cancelled", "failed", "pending"
});

// Colors
tg.setHeaderColor("#RRGGBB"); // Custom header color
tg.setBackgroundColor("#RRGGBB"); // Custom background color
tg.setBottomBarColor("#RRGGBB"); // Custom bottom bar color

// Permissions
tg.requestWriteAccess((granted) => {}); // Request PM write access
tg.requestContact((shared) => {}); // Request phone contact

// Home screen
tg.addToHomeScreen(); // Prompt add to home screen
tg.checkHomeScreenStatus((status) => {}); // 'added', 'missed', etc.

// Fullscreen
tg.requestFullscreen();
tg.exitFullscreen();

// Closing confirmation
tg.enableClosingConfirmation(); // Warn user before closing
tg.disableClosingConfirmation();

// Send data to bot (limited to 4096 bytes)
tg.sendData(JSON.stringify({ action: "submit" }));

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

34.84%
按下载量换算33

Claude

29.74%
按下载量换算28

Cursor

16.94%
按下载量换算16

Gemini CLI

10.4%
按下载量换算10

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

可疑

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。来源安全扫描存在 warning/failed 结果,不能写成本站确认安全。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills