Skip to content

docs: add formatting options documentation#12

Merged
KnightNiwrem merged 2 commits intomasterfrom
docs/formatting-options
Nov 29, 2025
Merged

docs: add formatting options documentation#12
KnightNiwrem merged 2 commits intomasterfrom
docs/formatting-options

Conversation

@KnightNiwrem
Copy link
Copy Markdown
Owner

@KnightNiwrem KnightNiwrem commented Nov 29, 2025

Add comprehensive documentation for all three Telegram formatting styles:

  • MarkdownV2.md: Full entity reference with syntax, MessageEntity types, and FormattedString mappings
  • HTML.md: HTML tag reference with all supported elements and nesting rules
  • Markdown.md: Legacy format documentation with deprecation notice and migration guide

Each document includes:

  • Entity reference tables
  • Detailed syntax examples
  • MessageEntity JSON structures
  • FormattedString usage examples
  • Nesting rules and limitations

Summary by CodeRabbit

  • Documentation
    • Added comprehensive HTML text formatting guide including supported elements, special character escaping, detailed usage examples, and nesting rules.
    • Added documentation for legacy Markdown formatting with deprecation notice and clear migration guidance to MarkdownV2.
    • Added detailed MarkdownV2 formatting guide covering syntax patterns, supported formatting types, nesting capabilities, language-specific code blocks, and comprehensive usage examples.

✏️ Tip: You can customize this high-level summary in your review settings.

Add comprehensive documentation for all three Telegram formatting styles:
- MarkdownV2.md: Full entity reference with syntax, MessageEntity types, and FormattedString mappings
- HTML.md: HTML tag reference with all supported elements and nesting rules
- Markdown.md: Legacy format documentation with deprecation notice and migration guide

Each document includes:
- Entity reference tables
- Detailed syntax examples
- MessageEntity JSON structures
- FormattedString usage examples
- Nesting rules and limitations
Copilot AI review requested due to automatic review settings November 29, 2025 08:30
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Nov 29, 2025

Warning

Rate limit exceeded

@KnightNiwrem has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 15 minutes and 35 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 910d00b and 72f2887.

📒 Files selected for processing (3)
  • docs/HTML.md (1 hunks)
  • docs/Markdown.md (1 hunks)
  • docs/MarkdownV2.md (1 hunks)

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Three new comprehensive documentation files added describing formatting options for Telegram Bot API integration: HTML formatting guide, legacy Markdown formatting guide (with deprecation notice), and MarkdownV2 formatting guide. Each documents how formatting syntax maps to MessageEntity types and FormattedString methods, with usage examples, nesting rules, and integration patterns.

Changes

Cohort / File(s) Summary
Documentation: Formatting Guides
docs/HTML.md, docs/Markdown.md, docs/MarkdownV2.md
Three new comprehensive formatting documentation files added. HTML.md maps HTML tags to MessageEntity types with nesting rules and usage examples. Markdown.md covers legacy Telegram Markdown format with deprecation notice and migration guidance. MarkdownV2.md provides detailed MarkdownV2 syntax reference including escaping rules, entity mappings, code block handling, and nesting restrictions. All include TypeScript and JSON usage snippets.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

  • Primary review focus: Verify accuracy of formatting syntax examples, MessageEntity mappings, and escaping rules against actual implementation
  • Confirm completeness and consistency of entity descriptions across all three guides
  • Check FormattedString API method names and usage patterns for correctness

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding comprehensive formatting options documentation for three Telegram formatting styles (MarkdownV2, HTML, and legacy Markdown).
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello @KnightNiwrem, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the project's documentation by introducing comprehensive guides for all three Telegram formatting modes: MarkdownV2, HTML, and the legacy Markdown. The new documentation aims to provide developers with clear, detailed references for each formatting style, including syntax, MessageEntity mappings, and usage examples with FormattedString, thereby improving clarity and ease of use for message formatting within the library.

Highlights

  • MarkdownV2 Documentation: Comprehensive documentation has been added for Telegram's MarkdownV2 formatting style, detailing entity references, syntax, MessageEntity JSON structures, FormattedString usage, and nesting rules.
  • HTML Documentation: New documentation for the HTML formatting style is now available, outlining HTML tag references, MessageEntity mappings, FormattedString examples, and nesting guidelines.
  • Legacy Markdown Documentation: Documentation for the legacy Markdown format has been introduced, including a clear deprecation notice, a migration guide to MarkdownV2, and an explanation of its limitations and unsupported features.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds comprehensive and well-structured documentation for Telegram's three formatting styles: HTML, MarkdownV2, and legacy Markdown. The new documents are clear and provide useful examples. I've identified a few minor inconsistencies and errors in the code examples and syntax descriptions. My review comments provide specific suggestions to correct these, which will improve the accuracy and clarity of the documentation for developers. Overall, this is an excellent and much-needed addition.

Comment thread docs/HTML.md Outdated
Comment on lines +60 to +69
import { fmt, bold, FormattedString } from "@grammyjs/parse-mode";

// Using entity tag
const result = fmt`${bold}bold text${bold}`;

// Using static method
const result = FormattedString.bold("bold text");

// Using instance method (alias)
const result = FormattedString.b("bold text");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The code examples in this block redeclare the const result variable multiple times, which is invalid TypeScript. This could confuse users who copy-paste the examples.

Additionally, the comment on line 68, // Using instance method (alias), is incorrect. FormattedString.b is a static method. An instance method is called on an object, e.g., new FormattedString("").b("bold text").

This feedback applies to most of the FormattedString Usage examples in this file and in Markdown.md.

Suggested change
import { fmt, bold, FormattedString } from "@grammyjs/parse-mode";
// Using entity tag
const result = fmt`${bold}bold text${bold}`;
// Using static method
const result = FormattedString.bold("bold text");
// Using instance method (alias)
const result = FormattedString.b("bold text");
import { fmt, bold, FormattedString } from "@grammyjs/parse-mode";
// Using entity tag
const fromFmt = fmt`${bold}bold text${bold}`;
// Using static method
const fromStatic = FormattedString.bold("bold text");
// Using static method (alias)
const fromAlias = FormattedString.b("bold text");

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accepted

Comment thread docs/HTML.md Outdated
Comment on lines +333 to +334
const result = fmt`${expandableBlockquote}Expandable quotation${expandableBlockquote}`;
const result = FormattedString.expandableBlockquote("Expandable quotation");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The text used in these examples, "Expandable quotation", is inconsistent with the text in the HTML syntax and MessageEntity examples ("Expandable quotation text"). For clarity and to avoid confusion about length properties, it would be best to use the same text across all examples for a given entity.

Also, please consider using different variable names to avoid redeclaring const result.

Suggested change
const result = fmt`${expandableBlockquote}Expandable quotation${expandableBlockquote}`;
const result = FormattedString.expandableBlockquote("Expandable quotation");
const fromFmt = fmt`${expandableBlockquote}Expandable quotation text${expandableBlockquote}`;
const fromStatic = FormattedString.expandableBlockquote("Expandable quotation text");

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accepted

Comment thread docs/MarkdownV2.md Outdated
| `[text](tg://user?id=123)` | user mention | `text_link` | `FormattedString.mentionUser(text, userId)` |
| `![emoji](tg://emoji?id=123)` | custom emoji | `custom_emoji` | `FormattedString.emoji(text, emojiId)` |
| `>blockquote` | blockquote | `blockquote` | `FormattedString.blockquote()` or `fmt\`${blockquote}...\`` |
| `**>expandable` | expandable blockquote | `expandable_blockquote` | `FormattedString.expandableBlockquote()` |
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The syntax for expandable blockquote is incomplete in the reference table. It should include the closing || characters to be accurate.

Suggested change
| `**>expandable` | expandable blockquote | `expandable_blockquote` | `FormattedString.expandableBlockquote()` |
| `**>expandable...||` | expandable blockquote | `expandable_blockquote` | `FormattedString.expandableBlockquote()` |

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accepted but be careful to escape properly as this is being written in a Markdown file table

Comment thread docs/MarkdownV2.md Outdated
Comment on lines +55 to +64
import { fmt, bold, FormattedString } from "@grammyjs/parse-mode";

// Using entity tag
const result = fmt`${bold}bold text${bold}`;

// Using static method
const result = FormattedString.bold("bold text");

// Using instance method
const result = new FormattedString("").bold("bold text");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The code examples in this block redeclare the const result variable multiple times, which is invalid TypeScript. This could confuse users who copy-paste the examples.

Please use different variable names for each example. This applies to other FormattedString Usage examples in this file as well.

Suggested change
import { fmt, bold, FormattedString } from "@grammyjs/parse-mode";
// Using entity tag
const result = fmt`${bold}bold text${bold}`;
// Using static method
const result = FormattedString.bold("bold text");
// Using instance method
const result = new FormattedString("").bold("bold text");
import { fmt, bold, FormattedString } from "@grammyjs/parse-mode";
// Using entity tag
const fromFmt = fmt`${bold}bold text${bold}`;
// Using static method
const fromStatic = FormattedString.bold("bold text");
// Using instance method
const fromInstance = new FormattedString("").bold("bold text");

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accepted

Comment thread docs/MarkdownV2.md Outdated

**MessageEntity:**
```json
{ "type": "expandable_blockquote", "offset": 0, "length": 80 }
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There's an inconsistency in the expandable blockquote example. The text in the syntax example (lines 288-290) is:
Expandable block quotation started\nExpandable block quotation continued\nThe last line of the block quotation
This text has a length of 107 characters (including newlines). However, the MessageEntity example shows "length": 80. Please correct the length in the MessageEntity to match the example text for consistency.

Suggested change
{ "type": "expandable_blockquote", "offset": 0, "length": 80 }
{ "type": "expandable_blockquote", "offset": 0, "length": 107 }

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accepted but the length is 108

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds comprehensive documentation for all three Telegram formatting styles (MarkdownV2, HTML, and legacy Markdown). The documentation provides developers with detailed references for entity types, syntax examples, MessageEntity JSON structures, FormattedString usage examples, and formatting rules for each style.

  • Complete entity reference tables mapping syntax to MessageEntity types and FormattedString methods
  • Detailed examples showing both entity tag and static method usage patterns
  • Nesting rules and limitations for each formatting style

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

File Description
docs/MarkdownV2.md Comprehensive reference for MarkdownV2 formatting including all entity types, escaping rules, and FormattedString method mappings
docs/Markdown.md Legacy Markdown documentation with deprecation notice, migration guide, and limitations explanation
docs/HTML.md HTML formatting reference with tag mappings, entity examples, and nesting rules

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/MarkdownV2.md Outdated

// With language
const result = fmt`${pre("python")}print("Hello")${pre}`;
const result = FormattedString.pre('print("Hello")', "python");
Copy link

Copilot AI Nov 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The static method FormattedString.pre() requires the language parameter as mandatory (not optional) according to the source code implementation. However, line 193 shows usage without language parameter: fmt\${pre()}pre-formatted code${pre}`. The entity tag function pre()accepts an optional language parameter, but the static method signature isstatic pre(text: Stringable, language: string)which requires it. Consider documenting both forms clearly or updating the examples to always include the language parameter (e.g.,FormattedString.pre(text, "")` for no language).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rejected

Comment thread docs/HTML.md Outdated

// With language
const result = fmt`${pre("python")}print("Hello")${pre}`;
const result = FormattedString.pre('print("Hello")', "python");
Copy link

Copilot AI Nov 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The static method FormattedString.pre() requires the language parameter as mandatory (not optional) according to the source code implementation. However, line 217 shows usage without language parameter: fmt\${pre()}pre-formatted code${pre}`. The entity tag function pre()accepts an optional language parameter, but the static method signature isstatic pre(text: Stringable, language: string)which requires it. Consider documenting both forms clearly or updating the examples to always include the language parameter (e.g.,FormattedString.pre(text, "")` for no language).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rejected

Comment thread docs/Markdown.md Outdated
Comment on lines +139 to +140

const result = fmt`${pre()}pre-formatted code${pre}`;
Copy link

Copilot AI Nov 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The example shows using the pre() entity tag without a language parameter, which is correct for the entity tag function. However, there's no example showing the static method FormattedString.pre() which would require a language parameter. For consistency with the other format docs (MarkdownV2.md and HTML.md), consider noting that the static method requires the language parameter, or explicitly mention that legacy Markdown doesn't support the static method with language.

Suggested change
const result = fmt`${pre()}pre-formatted code${pre}`;
// Using the entity tag function (recommended for legacy Markdown):
const result = fmt`${pre()}pre-formatted code${pre}`;
// Using the static method (for consistency with other formats):
// Note: In legacy Markdown, FormattedString.pre() does NOT accept a language parameter.
const result2 = fmt`${FormattedString.pre()}pre-formatted code${FormattedString.pre}`;

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rejected

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
docs/MarkdownV2.md (1)

127-142: Clarify spoiler syntax escape sequence.

Line 128 shows spoiler syntax as ||spoiler text|| but line 30 in the reference table shows \|\|spoiler\|\| with escaped pipes. This dual representation is correct but could be confusing. Consider adding a brief note explaining that the table shows the escaped form used in actual message text, while line 128 shows the markdown syntax concept.

Add a note before the table or inline comment clarifying the escape context:

 ### Spoiler
 
-**Syntax:** `||spoiler text||`
+**Syntax:** `||spoiler text||`
+
+> **Note:** When used in MarkdownV2 parse_mode, the pipes must be escaped as `\|\|` in the raw message text.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4758c8b and 910d00b.

📒 Files selected for processing (3)
  • docs/HTML.md (1 hunks)
  • docs/Markdown.md (1 hunks)
  • docs/MarkdownV2.md (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-11-29T03:43:25.220Z
Learnt from: CR
Repo: KnightNiwrem/parse-mode PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-11-29T03:43:25.220Z
Learning: Applies to src/format.ts : Use FormattedString fluent API chainable methods for building formatted messages

Applied to files:

  • docs/MarkdownV2.md
  • docs/Markdown.md
📚 Learning: 2025-11-29T03:43:41.309Z
Learnt from: CR
Repo: KnightNiwrem/parse-mode PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-29T03:43:41.309Z
Learning: Applies to src/format.ts : Add JSDoc to all public exports in `src/format.ts`

Applied to files:

  • docs/HTML.md
🪛 LanguageTool
docs/MarkdownV2.md

[grammar] ~200-~200: Use a hyphen to join words.
Context: ...ello")', "python"); ``` > Note: Pre entities cannot be combined with other f...

(QB_NEW_EN_HYPHEN)

docs/HTML.md

[grammar] ~224-~224: Use a hyphen to join words.
Context: ...ello")', "python"); ``` > Note: Pre entities cannot be combined with other f...

(QB_NEW_EN_HYPHEN)

🪛 markdownlint-cli2 (0.18.1)
docs/Markdown.md

13-13: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


27-27: Emphasis style
Expected: asterisk; Actual: underscore

(MD049, emphasis-style)


27-27: Emphasis style
Expected: asterisk; Actual: underscore

(MD049, emphasis-style)


34-34: Link text should be descriptive

(MD059, descriptive-link-text)


169-169: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


176-176: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Agent
🔇 Additional comments (7)
docs/Markdown.md (3)

1-52: Excellent deprecation documentation with clear migration path.

The deprecation notice (line 5-7) appropriately signals legacy status while the overview and entity reference provide essential context. The consistent table format comparing syntax, MessageEntity types, and FormattedString methods sets a strong foundation.


65-77: Verify FormattedString constructor and alias methods.

Line 76 references a .b("bold text") alias method. Ensure this alias (and similar ones like .i(), .s(), .u(), .a()) are consistently implemented across the library for all documented formatting types.


29-36: All FormattedString methods are properly exported and match the documentation.

Verification confirms that the static methods FormattedString.bold(), FormattedString.italic(), FormattedString.code(), FormattedString.link(), FormattedString.pre(), and FormattedString.mentionUser() are all properly defined in src/format.ts (lines 262, 280, 345, 355, 336, and 392 respectively) and exported via src/mod.ts. The table in docs/Markdown.md accurately reflects the available API.

docs/HTML.md (3)

1-40: Comprehensive HTML formatting guide with clear entity mappings.

The overview and entity escaping rules are well-organized. The reference table effectively maps HTML tags to MessageEntity types and FormattedString methods, making it easy for developers to cross-reference.


273-291: Verify custom emoji implementation details.

Line 277 shows the tg-emoji tag with emoji-id attribute. Confirm that:

  1. The emoji FormattedString method accepts a text parameter and emoji ID (as shown in line 290)
  2. The custom_emoji_id is correctly formatted in MessageEntity payloads (line 282)

295-335: Verify blockquote API surface.

Lines 307-335 document regular and expandable blockquotes. Ensure FormattedString.blockquote() and FormattedString.expandableBlockquote() methods accept string parameters as shown in the examples.

docs/MarkdownV2.md (1)

1-39: Excellent escaping documentation - clear and precise.

The special characters section (lines 11-18) effectively distinguishes between general escaping requirements and context-specific exceptions (pre/code, inline URLs). This precision prevents user errors. The entity reference table is comprehensive and well-organized.

Comment thread docs/MarkdownV2.md
Comment on lines +284 to +304
### Expandable Blockquote

**Syntax:**
```
**>Expandable block quotation started
>Expandable block quotation continued
>The last line of the block quotation||
```

**MessageEntity:**
```json
{ "type": "expandable_blockquote", "offset": 0, "length": 80 }
```

**FormattedString Usage:**
```typescript
import { fmt, expandableBlockquote, FormattedString } from "@grammyjs/parse-mode";

const result = fmt`${expandableBlockquote}Expandable quotation${expandableBlockquote}`;
const result = FormattedString.expandableBlockquote("Expandable quotation");
```
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Nov 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Telegram Bot API MarkdownV2 expandable blockquote syntax

💡 Result:

Short answer

  • MarkdownV2: use standard quote lines (each quoted line starts with "> "). It does NOT provide a way to mark a quote as "expandable". (gist.github.com)

  • Expandable blockquote: use HTML parse mode and the blockquote tag with the expandable attribute:

    . Clients render only first few lines and hide the rest until expanded. (ref.mtcute.dev)

Examples

  • MarkdownV2 blockquote:

    This is a quote
    Second line of quote
    (send with parse_mode=MarkdownV2). (gist.github.com)

  • Expandable (HTML):

    This is a long quote line 1 This is line 2 This is line 3 This is line 4 (hidden until expanded)
    (send with parse_mode=HTML). ([ref.mtcute.dev](https://ref.mtcute.dev/modules/_mtcute_html-parser?utm_source=openai))

Notes

  • Blockquote/expandable_blockquote are message entity types; they can’t be nested. Use HTML when you need the expandable behavior. (tgrm.oss.hagever.com)

Citations:


Remove the expandable blockquote section from MarkdownV2 documentation; this feature is not supported in MarkdownV2.

According to Telegram Bot API documentation, MarkdownV2 does not provide syntax for expandable blockquotes. MarkdownV2 only supports regular blockquotes using single > on each line. The expandable_blockquote entity type exists, but it can only be created using HTML parse mode with <blockquote expandable>…</blockquote> tags, not MarkdownV2 formatting.

Lines 284–304 incorrectly document **> as valid MarkdownV2 syntax for expandable blockquotes. This entire section should be removed from the MarkdownV2 documentation or moved to an HTML parse mode section if that is documented elsewhere in the file.

🤖 Prompt for AI Agents
In docs/MarkdownV2.md around lines 284 to 304, the "Expandable Blockquote"
section incorrectly documents a MarkdownV2 syntax that doesn't exist; remove
lines 284–304 (the entire Expandable Blockquote heading, syntax example,
MessageEntity block, and FormattedString usage) from the MarkdownV2
documentation, and if you want to preserve the content, relocate it under the
HTML parse-mode section with an appropriate note that expandable blockquotes are
only available via HTML (<blockquote expandable>...) rather than MarkdownV2.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rejected. Expandable blockquotes do exists in Markdown V2 as specified by Telegram Bot API.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🌐 Web query:

site:core.telegram.org MarkdownV2 expandable blockquote syntax

💡 Result:

Use MarkdownV2 blockquote lines starting with ">"; to make it expandable start the block with a bold ">" marker ("**>") then continue blockquote lines with ">" — the Bot API example shows this pattern (the expandable blockquote's hidden part ends with the expandability mark "||"). Example from core.telegram.org:

Block quotation...
**> The expandable block quotation started...
Expandable block quotation continued...
The last line of the expandable block quotation with the expandability mark||. [1]

Source: Telegram Bot API — MarkdownV2 examples. [1]


@KnightNiwrem, you're absolutely right, and I apologize for the incorrect review comment. The official Telegram Bot API documentation confirms that expandable blockquotes are indeed supported in MarkdownV2 using the **> syntax pattern you've documented.

The syntax starts with a bold marker (**>), continues with regular blockquote lines (>), and the expandable portion ends with the expandability mark (||). Your documentation is accurate. Thank you for the clarification!


🧠 Learnings used
Learnt from: CR
Repo: KnightNiwrem/parse-mode PR: 0
File: GEMINI.md:0-0
Timestamp: 2025-11-29T03:43:25.220Z
Learning: Applies to src/format.ts : Use FormattedString fluent API chainable methods for building formatted messages

- Fix redeclared const result variables in code examples (use unique names)
- Correct 'instance method' comments to 'static method' where applicable
- Use consistent text in expandable blockquote examples
- Add closing || to expandable blockquote syntax in MarkdownV2 table
- Fix expandable_blockquote MessageEntity length to 108
Copy link
Copy Markdown

@kilo-code-bot kilo-code-bot Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No Issues Found

3 files reviewed | Confidence: 95% | Recommendation: Merge

Review Details

Files: docs/HTML.md, docs/Markdown.md, docs/MarkdownV2.md

Checked:

  • Accuracy of API documentation against source code
  • Completeness of formatting method mappings
  • Correctness of MessageEntity type references
  • Consistency of usage examples
  • Security (no executable code or external links)

Findings:

  • All documented FormattedString methods exist in src/format.ts
  • Entity tag mappings are correct per src/entity-tag.ts
  • MessageEntity types match the library's type definitions
  • Usage examples demonstrate proper import and usage patterns
  • Documentation is comprehensive and well-structured

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/MarkdownV2.md
| `[text](tg://user?id=123)` | user mention | `text_link` | `FormattedString.mentionUser(text, userId)` |
| `![emoji](tg://emoji?id=123)` | custom emoji | `custom_emoji` | `FormattedString.emoji(text, emojiId)` |
| `>blockquote` | blockquote | `blockquote` | `FormattedString.blockquote()` or `fmt\`${blockquote}...\`` |
| `**>expandable...||` | expandable blockquote | `expandable_blockquote` | `FormattedString.expandableBlockquote()` |
Copy link

Copilot AI Nov 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The syntax shown for expandable blockquote appears incomplete. Based on the detailed syntax example in lines 288-290, this should be:

**>Expandable block...
>Continued text
>Last line||

The current syntax **>expandable...|| doesn't clearly show the multi-line nature and the placement of || at the end.

Suggested change
| `**>expandable...||` | expandable blockquote | `expandable_blockquote` | `FormattedString.expandableBlockquote()` |
| <pre><code>**&gt;Expandable block...<br>&gt;Continued text<br>&gt;Last line||</code></pre> | expandable blockquote | `expandable_blockquote` | `FormattedString.expandableBlockquote()` |

Copilot uses AI. Check for mistakes.
Comment thread docs/MarkdownV2.md
| `~strikethrough~` | ~~strikethrough~~ | `strikethrough` | `FormattedString.strikethrough()` or `fmt\`${strikethrough}...\`` |
| `\|\|spoiler\|\|` | spoiler | `spoiler` | `FormattedString.spoiler()` or `fmt\`${spoiler}...\`` |
| `` `code` `` | `code` | `code` | `FormattedString.code()` or `fmt\`${code}...\`` |
| ` ```pre``` ` | pre block | `pre` | `FormattedString.pre()` or `fmt\`${pre()}...\`` |
Copy link

Copilot AI Nov 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The table shows FormattedString.pre() without parameters, but according to the implementation in src/format.ts line 355, the pre static method requires a language parameter: static pre(text: Stringable, language: string).

While the entity tag function pre() accepts an optional language parameter (as shown correctly in line 193), the static method does not have an overload for the no-language case. This should either be:

  • FormattedString.pre(text, language) to match the required signature, or
  • The implementation should be updated to make language optional
Suggested change
| ` ```pre``` ` | pre block | `pre` | `FormattedString.pre()` or `fmt\`${pre()}...\`` |
| ` ```pre``` ` | pre block | `pre` | `FormattedString.pre(text, "")` or `fmt\`${pre()}...\`` |

Copilot uses AI. Check for mistakes.
Comment thread docs/HTML.md
| `<s>`, `<strike>`, `<del>` | `strikethrough` | `FormattedString.strikethrough()` or `fmt\`${strikethrough}...\`` |
| `<span class="tg-spoiler">`, `<tg-spoiler>` | `spoiler` | `FormattedString.spoiler()` or `fmt\`${spoiler}...\`` |
| `<code>` | `code` | `FormattedString.code()` or `fmt\`${code}...\`` |
| `<pre>` | `pre` | `FormattedString.pre()` or `fmt\`${pre()}...\`` |
Copy link

Copilot AI Nov 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The table shows FormattedString.pre() without parameters, but according to the implementation in src/format.ts line 355, the pre static method requires a language parameter: static pre(text: Stringable, language: string).

While the entity tag function pre() accepts an optional language parameter (as shown correctly in line 217), the static method does not have an overload for the no-language case. This should either be:

  • FormattedString.pre(text, language) to match the required signature, or
  • The implementation should be updated to make language optional
Suggested change
| `<pre>` | `pre` | `FormattedString.pre()` or `fmt\`${pre()}...\`` |
| `<pre>` | `pre` | `FormattedString.pre(text, language)` or `fmt\`${pre()}...\`` |

Copilot uses AI. Check for mistakes.
Comment thread docs/Markdown.md
| `*bold*` | *bold* | `bold` | `FormattedString.bold()` or `fmt\`${bold}...\`` |
| `_italic_` | _italic_ | `italic` | `FormattedString.italic()` or `fmt\`${italic}...\`` |
| `` `code` `` | `code` | `code` | `FormattedString.code()` or `fmt\`${code}...\`` |
| ` ```pre``` ` | pre block | `pre` | `FormattedString.pre()` or `fmt\`${pre()}...\`` |
Copy link

Copilot AI Nov 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The table shows FormattedString.pre() without parameters, but according to the implementation in src/format.ts line 355, the pre static method requires a language parameter: static pre(text: Stringable, language: string).

While the entity tag function pre() accepts an optional language parameter (as shown correctly in line 140), the static method does not have an overload for the no-language case. This should either be:

  • FormattedString.pre(text, language) to match the required signature, or
  • The implementation should be updated to make language optional
Suggested change
| ` ```pre``` ` | pre block | `pre` | `FormattedString.pre()` or `fmt\`${pre()}...\`` |
| ` ```pre``` ` | pre block | `pre` | `FormattedString.pre(text, language)` or `fmt\`${pre(language)}...\`` |

Copilot uses AI. Check for mistakes.
@KnightNiwrem KnightNiwrem merged commit 78fe9c2 into master Nov 29, 2025
7 checks passed
@KnightNiwrem KnightNiwrem deleted the docs/formatting-options branch November 29, 2025 09:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants