Skip to content

JSX

npmJSRJSR Score

Use JSX to format Telegram bot messages and build keyboards. Instead of chaining format, bold, italic functions, write familiar HTML-like syntax that compiles into GramIO's FormattableString and InlineKeyboard/Keyboard objects.

No React dependency required — the package provides its own JSX runtime.

Installation

sh
npm install @gramio/jsx
sh
yarn add @gramio/jsx
sh
pnpm add @gramio/jsx
sh
bun add @gramio/jsx

Configuration

Add the JSX runtime to your tsconfig.json:

json
{
    "compilerOptions": {
        "jsx": "react-jsx",
        "jsxImportSource": "@gramio/jsx"
    }
}

Your files should use the .tsx extension.

Usage

Text formatting

tsx
import { Bot } from "gramio";

const bot = new Bot(process.env.BOT_TOKEN!)
    .command("start", (context) =>
        context.send(<b>Hello!</b>)
    );

bot.start();

All Telegram formatting entities are supported as JSX elements:

tsx
await context.send(
    <>
        <b>Bold text</b><br />
        <i>Italic text</i><br />
        <u>Underlined text</u><br />
        <s>Strikethrough</s><br />
        <spoiler>Hidden text</spoiler><br />
        <code>inline code</code><br />
        <pre>{`code block
with multiple lines`}</pre><br />
        <blockquote>Simple blockquote</blockquote><br />
        <blockquote expandable>Expandable blockquote</blockquote><br />
        <a href="https://gramio.dev">GramIO</a><br />
        <mention id={123456789}>User</mention><br />
        <custom-emoji emojiId="5222106016283378623">emoji</custom-emoji>
    </>
);

Formatting elements reference

ElementDescriptionExample
<b>Bold text<b>bold</b>
<i>Italic text<i>italic</i>
<u>Underlined text<u>underline</u>
<s>Strikethrough text<s>strikethrough</s>
<spoiler>Spoiler (hidden) text<spoiler>hidden</spoiler>
<code>Inline code<code>code</code>
<pre>Code block<pre>code block</pre>
<blockquote>Blockquote<blockquote>quote</blockquote>
<a href="...">Hyperlink<a href="https://gramio.dev">link</a>
<mention id={...}>User mention by ID<mention id={123}>user</mention>
<custom-emoji emojiId="...">Custom emoji<custom-emoji emojiId="123">emoji</custom-emoji>
<br />Line breaktext<br />next line

The <blockquote> element supports an optional expandable boolean prop for expandable blockquotes.

Nesting is supported — for example, <b><i>bold italic</i></b>.

Inline keyboard

Pass a <keyboard inline> element to reply_markup:

tsx
await context.send(
    <b>Choose an option:</b>,
    {
        reply_markup: (
            <keyboard inline>
                <row>
                    <button callbackData="action1">Click me</button>
                    <button url="https://gramio.dev">Open link</button>
                </row>
                <row>
                    <button switchToCurrentChat="query">Inline search</button>
                </row>
            </keyboard>
        ),
    }
);

Inline button props

PropTypeDescription
callbackDatastringCallback data for button press
urlstringURL to open
webApp{ url: string }WebApp to open
loginUrlTelegramLoginUrlLogin URL
switchToChatstringSwitch inline query to another chat
switchToCurrentChatstringSwitch inline query to current chat
switchToChosenChatstring | TelegramSwitchInlineQueryChosenChatSwitch to chosen chat
copyTextstringCopy text to clipboard
gameTelegramCallbackGameCallback game

Reply keyboard

Omit the inline prop on <keyboard>:

tsx
await context.send("Choose an option:", {
    reply_markup: (
        <keyboard oneTime placeholder="Select...">
            <row>
                <button requestContact>Send contact</button>
                <button requestLocation>Send location</button>
            </row>
            <row>
                <button>Simple button</button>
            </row>
        </keyboard>
    ),
});

Reply keyboard props

PropTypeDescription
persistentbooleanAlways show the keyboard
selectivebooleanShow only to specific users
resizedbooleanResize the keyboard to fit
oneTimebooleanHide after button press
placeholderstringInput field placeholder

Reply button props

PropTypeDescription
requestContactbooleanRequest user's phone contact
requestLocationbooleanRequest user's location
requestChatTelegramKeyboardButtonRequestChatRequest a chat selection
requestPoll{ type: "quiz" | "regular" }Request poll creation
webApp{ url: string }Open a WebApp

Full example

tsx
import { Bot } from "gramio";

const bot = new Bot(process.env.BOT_TOKEN!)
    .command("start", (context) =>
        context.send(<b>Hello!</b>)
    )
    .command("demo", async (context) => {
        await context.reply(
            <>
                <b>Bold text</b><br />
                <i>Italic text</i><br />
                <u>Underlined</u><br />
                <s>Strikethrough</s><br />
                <spoiler><b>Bold spoiler</b></spoiler><br />
                <a href="https://gramio.dev">GramIO</a><br />
                <mention id={context.from!.id}>You</mention><br />
                <code>print("Hello")</code><br />
                <pre>{`function greet() {
    console.log("Hello!");
}`}</pre>
            </>,
            {
                reply_markup: (
                    <keyboard inline>
                        <row>
                            <button callbackData="test">Click me</button>
                            <button url="https://gramio.dev">Docs</button>
                        </row>
                    </keyboard>
                ),
            }
        );
    })
    .onStart(console.log);

bot.start();