Skip to content

Text formatting ​

Plain strings are parsed with the app's parseMode, which you can override per content or per step:

parseModemeaning
markdown (default)**bold** *italic* _italic_ __underline__ ~~strike~~ ||spoiler|| `code` ```pre``` [text](url) > quote # heading - bullet
htmlraw Telegram HTML
markdownv2raw Telegram MarkdownV2
plainno formatting

The Markdown dialect is predictable:

  • _ inside words (snake_case, URLs) never becomes italic.
  • Unmatched markers are shown as-is.
  • \ escapes the next character, except in code: inside `code` and code blocks, text is shown as written (only \\ and \` are escapes), so `\d+` stays \d+.
  • Code blocks take any language name: ```c++, ```c#.

Put user data in md / html templates. They escape every interpolated value, so a user named [free](https://evil) can't inject a link:

ts
text: md`Hello **${user.name}**, you owe ${amount}`
text: html`Hello <b>${user.name}</b>`
text: [md`**${title}**`, 'a plain line follows parseMode']  // mixing is fine (not with parseMode 'markdownv2')

Fragments nest: md keeps nested md fragments, html keeps nested md and html fragments. An html fragment inside md is escaped (its tags show as text).

escapeMarkdown, escapeHTML and escapeMarkdownV2 are also available for manual escaping.

For headings, tables, task lists, formulas and pictures in one message, see Rich messages: rich instead of text, in Telegram's Rich Markdown (GitHub-style, so __x__ is bold there). md fragments work there too, escaping their values for it (escapeRichMarkdown).

Try it ​

A whole bot. On the docs site it runs next to the code, in a Telegram simulator.

MIT licensed