Telegram recently introduced Rich Messages — a new HTML-based formatting system that lets you build beautifully styled messages with headings, lists, tables, collages, maps, and much more.
But if you're writing a Telegram bot in TypeScript/JavaScript, you might have noticed that there's no ready-made builder for this new format yet. You have to manually write HTML strings, escape content, and keep track of nesting, media limits, and text length — which is tedious and error‑prone.
That's why I built tg-rich-messages — a small, zero‑dependency library that does all the heavy lifting for you.
✨ What it does
It provides a clean, typed API to build rich messages programmatically. You can mix and match inline and block elements, and the library will generate the correct HTML for Telegram's sendRichMessage method.
Features:
- All inline formatting: bold, italic, underline, strikethrough, spoiler, code, marked, sub, sup, links, mentions, emoji, date/time, and more.
- All block elements: headings (1–6), paragraphs, preformatted code, lists (ordered/unordered, with checkboxes), blockquotes, pullquotes, tables (alignment, colspan, rowspan, stripes), details (expandable), maps, collages, slideshows.
- Media blocks: photo, video, animation, audio, voice — with captions and credits.
- Full validation: checks text length (≤32768 chars), media count (≤50), total blocks (≤500), and nesting depth (≤16).
- Tree‑shakeable, no runtime dependencies.
- Tagged template literal (
fmtRich) for natural inline mixing.
🚀 Quick Start
Install the package:
npm install tg-rich-messages
Then build your message:
import { doc, bold, italic, paragraph, heading, list, code, fmtRich } from 'tg-rich-messages';
// Using the builder API
const message = doc(
heading(1, 'Welcome'),
paragraph([bold('Hello'), ' ', italic('world'), '!']),
list(
[
'First item',
{ content: code('code example'), checkbox: true, checked: true },
{ content: 'Ordered item', value: 7, type: 'a' },
],
{ ordered: true, start: 7 },
)
);
// Render to HTML
const html = message.toHTML();
// Get InputRichMessage payload for sendRichMessage
const payload = message.toInputRichMessage({
skipEntityDetection: true
});
Or use the template literal:
const message = fmtRich`
${bold`Hello`} ${italic`world`}!
Here is some ${code`inline code`}.
`;
console.log(message.toHTML());
// <p><b>Hello</b> <i>world</i>!<br>Here is some <code>inline code</code>.</p>
📦 Example with a Telegram Bot
Send the rich message via the Bot API:
await fetch(`https://api.telegram.org/bot${TOKEN}/sendRichMessage`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
chat_id: chatId,
rich_message: message.toInputRichMessage()
})
});
🔍 Validation
The built‑in validate() method checks:
- Text length (actual UTF‑8 characters, not bytes)
- Number of media attachments (≤50)
- Total blocks (≤500)
- Nesting depth (≤16)
This prevents you from sending messages that Telegram would reject.
🧩 Why I built it
I needed a clean, typed way to generate rich messages for my own Telegram bot. I couldn't find an existing JS/TS library that did this, so I built one for myself — and decided to share it in case others find it useful too.
It's not a long‑term maintained project, but I believe it's already feature‑complete for most use cases. Pull requests are welcome!
📎 Links
- GitHub: https://github.com/vdistortion/tg-rich-messages
- npm: https://www.npmjs.com/package/tg-rich-messages
- Telegram API docs: Rich Messages
🙌 Feedback
If you try it out, let me know what you think! Issues and suggestions are welcome on GitHub.
Happy building! 🚀























