Telegram Mini Apps Next.js Template

repository·master·Indexed 18 days ago

https://github.com/telegram-mini-apps/nextjs-template

A Next.js template for building Telegram Mini Apps, integrating @telegram-apps/sdk, TON Connect, and Telegram UI. It includes built-in components for layout management (Page, Root), external navigation (Link), and data rendering (DisplayData), as well as utilities for BEM class generation and Telegram environment mocking for development.

Tokens
4.3K
Snippets
17
Records
20
Agent score
62%

What's inside telegram-mini-apps-nextjs-template

  1. Run the application in development mode

    master

    You can develop and test the application outside of Telegram by running the standard dev script. The template uses src/hooks/useTelegramMock.ts and the mockTelegramEnv function to simulate the Telegram environment, allowing @telegram-apps/sdk to function in a standard browser.

    pnpm run dev
  2. Run the application inside Telegram

    master

    To test the application within the actual Telegram environment, you must use an HTTPS link.

    1. Run the application with a self-signed SSL certificate:
      pnpm run dev:https
    2. Open the local link (e.g., https://localhost:3000) in your browser. If you see an SSL warning, click Proceed to localhost (unsafe).
    3. Provide the link https://127.0.0.1:3000 (Note: https://localhost:3000 is invalid for BotFather) to @BotFather as your Mini App link.
    4. Launch the app via Telegram Web.
    pnpm run dev:https
  3. How the Root component manages Telegram Mini App initialization

    master

    The Root component serves as the main application provider. Because Telegram Mini Apps have limitations with Server Side Rendering (SSR), the Root component uses a useDidMount hook to ensure the application only renders the full UI on the client side. During the initial server-side pass, it renders a loading state (<div className="root__loading">Loading</div>).

    Once mounted, it wraps the application in several providers:

    • TonConnectUIProvider: Configured with a manifest at /tonconnect-manifest.json for TON wallet connectivity.
    • AppRoot (from @telegram-apps/telegram-ui): Configures the visual appearance (dark/light mode) and the platform-specific UI behavior based on Telegram's launch parameters.
    • ErrorBoundary: Catches runtime errors and displays the ErrorPage component.

    It also automatically synchronizes the application's locale with the user's Telegram language code using setLocale from the initData.user.language_code.

    import { Root } from '@/components/Root/Root';
    
    // Usage in layout.tsx or similar entry point
    export default function Layout({ children }: { children: React.ReactNode }) {
      return (
        <Root>
          {children}
        </Root>
      );
    }
  4. Configure the Root component appearance and platform

    master

    The Root component automatically derives the Telegram UI appearance and platform settings from the SDK:

    • Appearance: Uses miniApp.isDark to toggle between 'dark' and 'light' modes.
    • Platform: Maps lp.tgWebAppPlatform to @telegram-apps/telegram-ui platform types. Specifically, if the platform is 'macos' or 'ios', it uses 'ios'; otherwise, it defaults to 'base'.

    Note that these values are reactive via the @tma.js/sdk-react signals (useSignal).

  5. Configure internationalization locales and time zone

    master

    The project uses a central configuration for internationalization (i18n). You can define the defaultLocale, the supported locales array, and a localesMap which maps locale keys to human-readable titles for UI selection. The timeZone is also globally configured for date/time handling.

    To add a new language, update the locales array and add a corresponding entry to the localesMap object.

    export const defaultLocale = 'en';
    
    export const timeZone = 'Europe/Amsterdam';
    
    export const locales = [defaultLocale, 'ru'] as const;
    
    export const localesMap = [
      { key: 'en', title: 'English' },
      { key: 'ru', title: 'Русский' },
    ];
  6. Available NPM Scripts

    master

    Use pnpm run {script} to execute the following commands:

    • dev: Runs the application in development mode.
    • dev:https: Runs the application in development mode using a self-signed SSL certificate (required for testing inside Telegram).
    • build: Builds the application for production.
    • start: Starts the Next.js server in production mode.
    • lint: Runs eslint to ensure code quality.
    pnpm run build
  7. Initialize the Telegram Mini App with init()

    master

    The init function is the primary entrypoint for setting up the application environment, configuring the @tma.js/sdk-react SDK, and mounting essential Telegram Mini App components. It handles debug mode, Eruda console integration, and provides a macOS-specific environment mock to bypass known client bugs.

    Options

    OptionTypeDescription
    debugbooleanEnables debug mode in @tma.js/sdk-react.
    erudabooleanIf true, dynamically imports and initializes Eruda (a mobile web console).
    mockForMacOSbooleanIf true, mocks the Telegram environment to fix issues with web_app_request_theme and web_app_request_safe_area on the macOS Telegram client.

    Side Effects

    When called, init performs the following:

    • SDK Setup: Calls setDebug and initSDK.
    • Eruda: If enabled, initializes Eruda and positions it at the top-right corner.
    • macOS Mocking: If mockForMacOS is enabled, it intercepts specific Telegram events to return correct theme parameters and safe area values.
    • Component Mounting: Automatically mounts backButton, initData, miniApp, and viewport, and binds their respective CSS variables.
    import { init } from './core/init';
    
    await init({
      debug: true,
      eruda: true,
      mockForMacOS: false
    });
  8. Merge multiple class sets with mergeClassNames()

    master

    The mergeClassNames function is used to merge multiple partial class objects into a single object. It is particularly useful when you have different sets of conditional classes (represented as objects) and want to combine them into one cohesive set of class definitions.

    It expects an array of objects. If a key exists in multiple objects, the values for that key are merged using the classNames logic.

    import { mergeClassNames } from './src/css/classnames';
    
    const base = { btn: 'btn', active: true };
    const theme = { btn: 'btn-primary', large: true };
    
    const merged = mergeClassNames(base, theme);
    // Result: { btn: 'btn btn-primary', active: '', large: '' } 
    // Note: The type system ensures keys are correctly mapped.
  9. Use the DisplayData component

    master

    The DisplayData component is a UI component used to render a list of data rows within a Section. It automatically formats different types of values into appropriate UI elements like links, checkboxes, or color indicators.

    Row Types

    Each object in the rows array must follow the DisplayDataRow type:

    • Link type: { type: 'link', value?: string } — Renders an "Open" link using the provided URL.
    • ReactNode type: { value: ReactNode } — Renders custom React elements. The component applies special logic based on the type of value:
      • string: If the string is a valid RGB color (detected via isRGB), it renders an <RGB /> component. Otherwise, it renders the string.
      • boolean: Renders a disabled <Checkbox /> indicating the state.
      • undefined: Renders an empty placeholder.

    Props

    • rows: An array of DisplayDataRow objects (required).
    • header: Optional React node to display as the section header.
    • footer: Optional React node to display as the section footer.
    import { DisplayData, type DisplayDataRow } from '@/components/DisplayData/DisplayData';
    
    const rows: DisplayDataRow[] = [
      { title: 'Status', value: true }, // Renders a disabled checkbox
      { title: 'Color', value: '#ff0000' }, // Renders an RGB color component
      { type: 'link', value: 'https://t.me/example' }, // Renders an "Open" link
      { title: 'Custom', value: <span>Custom Content</span> }, // Renders raw ReactNode
      { title: 'Empty', value: undefined }, // Renders *empty*
    ];
    
    export const MyComponent = () => (
      <DisplayData 
        header={<span>My Data Section</span>} 
        rows={rows} 
      />
    );
  10. Configure back button visibility in the Page component

    master

    The Page component accepts a back prop to control the Telegram backButton visibility:

    PropTypeDefaultDescription
    backbooleantrueDetermines if the Telegram back button should be shown on this page.

    When back is enabled, the component also attaches an onClick listener to the backButton that invokes router.back() from next/navigation.