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();