Available in Englishvust.ai
vust

Markdown · MD to Rendered HTML

Render Markdown to HTML Preview

See how your Markdown will look — rendered as styled HTML in your browser. Useful for previewing before publishing or sharing.

Free · No signup · Instant

Free, no signup. Up to 1 MB per request.

Live previewStyle-faithfulInstant render

Markdown to rendered HTML examples

Paste real Markdown in the left column, see the rendered HTML output on the right.

Full README

Markdown

# Project ## Installation ```bash npm install ```

rendered HTML

<rendered: heading + code block styled>

Blog post with code

Markdown

## How it works This is **important**. ```js const x = 1; ```

rendered HTML

<rendered: styled heading + bold + code block>

GFM table

Markdown

| Name | Score | |------|-------| | Alice | 95 |

rendered HTML

<rendered: styled table>

How Markdown-to-rendered HTML conversion works

01

Paste Markdown — Paste your Markdown into the input pane.

02

Preview — See the rendered HTML preview update in real-time.

03

Share or export — Copy the HTML or use the rendered view for screenshots.

Markdown edge cases we handle

Faithful rendering

The preview matches what GitHub and most blog platforms render — no custom styles bleed in.

Code-block highlighting

Fenced code blocks with language hints get syntax highlighting in the preview.

Math expressions

Inline and block math expressions (`$x^2$` and `$$x^2$$`) are rendered using KaTeX.

Image lazy-load

Images load lazily with alt-text fallback shown until the image loads.

Markdown source vs rendered output

Markdown source is what you type. Rendered output is what someone sees after the source passes through a renderer. The two are not the same. A source line containing **bold** is six characters long with two asterisks at each end; the rendered version is the word bold displayed in heavy weight, with no asterisks visible. The source is for authors; the rendered output is for readers.

The Markdown-to-rendered conversion takes Markdown source and produces a representation that simulates the reader's view. In the VUST context, the rendered representation is specifically Telegram's entity-formatted message: the plain message text plus an array of formatting entities that a Telegram client interprets natively. This is the form the bot at @vustMarkdownBot sends to a chat, and the form a Telegram client renders as styled text.

The conversion is the bridge between Markdown source — easy to write, easy to version-control, portable across documentation tools — and Telegram's native rendering — what your audience actually sees in chat. If you draft your bot's outgoing messages in Markdown but Telegram doesn't accept Markdown syntax in messages directly (without specific parse-mode flags that have their own quirks), the rendered conversion is what you actually send.

What "rendered" means for Telegram

Telegram clients display messages with formatting based on the entities array that accompanies the message text. A message with a bold entity at offset 0, length 5 displays the first 5 characters as bold. The entities are positional; they do not appear in the visible text, only in the underlying API payload.

The rendered output of this converter is the same kind of payload: a text string and an entities array. The bot at @vustMarkdownBot passes both to the Telegram Bot API when sending the message; the receiving Telegram client renders the entities as visible formatting.

This is different from sending a Markdown-formatted string with parse_mode: 'MarkdownV2'. The MarkdownV2 mode requires escaping special characters and has strict parsing rules; small mistakes break the message or leak literal characters. The entity-formatted approach sidesteps both problems — the text is the visible text, the entities are the formatting, and the two are independent.

The "rendered" framing is therefore Telegram-specific: the conversion produces data that Telegram clients render as the styled output. Other consumers (a bot that forwards to Slack, a tool that exports to a database) can use the entities array as semantic metadata — the same data describes the formatting whether or not a particular client renders it natively.

How the engine builds the entity output

The conversion is a two-step path:

  1. Parse the Markdown source into an AST. The parser uses marked configured for GitHub-Flavored Markdown. Block constructs (paragraphs, headings, lists, blockquotes, code blocks) and inline constructs (bold, italic, strikethrough, code, links) are recognized and turned into AST nodes.
  2. Render the AST as Telegram entities. The renderer walks the AST, accumulating text into a single string and emitting entity objects whose offsets and lengths reference positions in the accumulated text. The output is { text, entities } matching the Telegram Bot API format.

For each AST node, the renderer makes a deliberate choice about how to map it:

  • Paragraphs contribute their text plus a \n\n separator. No entity is emitted.
  • Bold, italic, underline, strikethrough wrap their inner text and emit the corresponding entity (bold, italic, underline, strikethrough) with offset and length of the text region.
  • Inline code appends its text and emits a code entity.
  • Code blocks append the code content followed by \n\n, and emit a pre entity covering the code content.
  • Links wrap their inner text and emit a text_link entity with the URL.
  • Bullet lists prefix each item with (a Unicode bullet character) and append \n between items.
  • Numbered lists prefix each item with N. and append \n between items.
  • Blockquotes emit a blockquote entity covering the contained text.
  • Line breaks inside a paragraph contribute \n.

UTF-16 offset arithmetic is used throughout. The Telegram Bot API expects offsets and lengths in UTF-16 code units; emoji and many CJK characters span two code units, so naive string.length is correct but Array.from(string).length is not. The renderer accumulates length in UTF-16 units explicitly.

Before/after — source and rendered preview

A Markdown paragraph with mixed inline emphasis goes in:

The **convert()** function is *synchronous* and returns a `result` object.

The rendered output is a text string and an entities array:

{
  "text": "The convert() function is synchronous and returns a result object.",
  "entities": [
    { "type": "bold", "offset": 4, "length": 11 },
    { "type": "italic", "offset": 26, "length": 11 },
    { "type": "code", "offset": 53, "length": 6 }
  ]
}

When a Telegram client renders this, the user sees: "The convert() function is synchronous and returns a result object." with bold, italic, and inline code rendered visually.

A bullet list with a link goes in:

- First item
- Second item with [link](https://example.com)
- Third item

Rendered output:

{
  "text": "• First item\n• Second item with link\n• Third item\n\n",
  "entities": [
    { "type": "text_link", "offset": 32, "length": 4, "url": "https://example.com" }
  ]
}

A blockquote with two paragraphs goes in:

> The mind is everything.
> 
> What you think, you become.

Rendered output:

{
  "text": "The mind is everything.\n\nWhat you think, you become.\n",
  "entities": [
    { "type": "blockquote", "offset": 0, "length": 52 }
  ]
}

The blockquote entity covers both paragraphs as one quoted block. The chat client renders the entire range with the blockquote visual treatment.

Constructs Telegram cannot render

Several Markdown constructs do not have a Telegram entity equivalent and are dropped or approximated:

Headings. Telegram does not have a heading entity. A ## Section title line does not produce a styled heading in the rendered output. In current engine behavior, heading nodes are skipped from the entity output entirely — the heading text disappears from the rendered message. If you need heading-like emphasis, manually convert headings to bold paragraphs in your Markdown source before rendering.

Tables. GFM pipe tables are syntactically valid Markdown but Telegram has no table entity. The current engine flattens table rows to their content text, joined approximately. For data that needs tabular display in Telegram, the practical workaround is to format the data as a code block, which preserves alignment using monospace font: triple-backtick fences in the source produce a pre entity that renders as a fixed-width block.

Images. Inline image syntax (![alt](url)) is parsed by the Markdown engine but Telegram does not embed images via entities — images are sent as separate Bot API calls (sendPhoto). The rendered output does not include images. For a bot workflow that mixes text and images, send the images as separate messages or attached to a text caption.

Footnotes, definition lists, task lists. GFM and extended-Markdown features without Telegram counterparts are either rendered as approximate text or dropped. Plan your Markdown source within the construct set Telegram supports.

Spoiler tags. Some Markdown variants support ||spoiler|| syntax. Telegram does have a spoiler entity, but the current engine does not parse spoiler syntax in Markdown source. To produce spoiler-formatted output, the source must come through Telegram entities directly (e.g., from another forwarded message), not via the Markdown-to-rendered path.

Mentions, hashtags, custom emoji. Telegram has these as entities but they are platform-specific references, not Markdown syntax. The Markdown source has no canonical way to express them; the rendered output does not produce them.

Length, code blocks, and message limits

Telegram messages have a 4096-character cap (UTF-16 units). Markdown source typically produces rendered text shorter than the source itself — formatting markers are dropped — but watch for these cases:

Code blocks preserve all whitespace literally. A Markdown code block with 100 lines of code adds 100 lines of text to the rendered output. Long source files exported as Markdown can exceed the cap. If your bot output includes long code blocks, pre-split or paginate.

List items add bullet/number prefixes. A list with 100 items adds at least 200 characters of bullet markers and newlines. Long lists from Markdown source can grow more than expected in rendered output.

Blockquotes do not visibly add characters but do consume entity slots. Telegram limits the total number of entities per message; a message with hundreds of small formatted regions may exceed it. The bot framework does not always surface this clearly — if rendered output is missing some formatting, entity overflow is a likely cause.

Nested formatting compounds. A bold-italic-underlined word produces three entities for the same text range. Three entities × 4 bytes per entity in the API payload × hundreds of formatted regions adds up. For documents with heavy formatting, prefer one consistent emphasis level.

The conversion does not enforce length limits or split long messages — that is the bot caller's responsibility. The conversion produces the rendered representation; the caller decides what to do with it.

Pairing the preview with the bot

The Markdown-to-rendered conversion has two practical surfaces:

The web tool at vust.ai/markdown/markdown-to-rendered accepts Markdown source and shows the rendered preview as text plus an entity array. This is the right place to draft and verify a bot's outgoing messages — write the Markdown, see what Telegram will render, adjust the source, repeat.

The Telegram bot at @vustMarkdownBot accepts Markdown source as input and replies with the rendered version directly in the chat. The rendered reply is what your audience would see if your custom bot sent that message. Send Markdown to the bot, get the rendered preview as a real message — the round-trip is fast and visual.

The pairing is most useful for bot developers and content authors. Drafting bot replies in Markdown source keeps them version-controlled and reviewable; converting at send time produces the rendered version Telegram clients understand. The conversion is the deterministic bridge.

For ad-hoc message formatting (a one-off announcement, a styled post in a channel), the bot path is fastest — draft in Markdown, forward to the bot, copy the rendered reply, paste into the destination channel. For programmatic use cases (a custom bot that sends formatted messages on a schedule), the engine is available as a package; integrate the conversion into your bot's outbound message pipeline.

The result is a deliberate, lossy-where-it-must-be, faithful-where-it-can-be conversion from Markdown source to Telegram-rendered output. It tells you upfront which constructs survive and which don't, and gives you a deterministic preview of the formatting your audience will see.

Frequently asked questions

Process bigger files in @vustMarkdownBot

500-character free conversions in chat — pay-as-you-go for longer text.

Open Telegram bot
    Markdown Renderer — Live HTML Preview — VUST