Hello world!
") result.markdown # => "Hello **world**!" ``` `result` is a [`Markbridge::Conversion`](/concepts/result-objects/) — `.markdown`, plus `.unknown_tags`, `.errors` for migration use. To get the AST: ```ruby parse = Markbridge.parse_html("link") parse.ast # => AST::Document(Url("link", href: "https://example.com")) ``` ## Supported tags | HTML | Renders as | AST node | | --------------------------------- | ------------------------------------------------ | ------------------------------------ | | ``, `` | `**bold**` | `AST::Bold` | | ``, `` | `*italic*` | `AST::Italic` | | ``, `` | Code span; fenced block for multiline content | `AST::Code` |
| `` | Fenced code block, including single-line content | `AST::Code` |
| ``–`` | `#` through `######` headings | `AST::Heading` |
| `` | `[text](href)` | `AST::Url` |
| `
` | `` | `AST::Image` |
| `` | `[quote]…[/quote]` | `AST::Quote` |
| ``, `` | `- item` / `1. item` | `AST::List` |
| `- ` | List item | `AST::ListItem` |
| `
`, ``, ``, ` ` | GFM table | `AST::Table` |
| `
` | Hard line break | `AST::LineBreak` |
| `
` | `---` | `AST::HorizontalRule` |
| `` | Paragraph spacing | — (transparent) |
``, `
`, `` are transparent — their children are processed as if the wrapper weren’t there. Unregistered tags are skipped, but their children are still processed (graceful degradation).
For the authoritative list, see [`HandlerRegistry.default`](https://github.com/discourse/markbridge/blob/main/lib/markbridge/parsers/html/handler_registry.rb).
## Code languages
For syntax highlighting, the parser uses the first valid language from:
1. A `language-*` class on the element.
2. A `language-*` class on its direct `` child.
3. The element’s `lang` attribute.
4. A single class on the element or its direct `` child.
The language must contain only letters, digits, underscores, plus signs, or hyphens, and start with a letter or digit. A class list such as `hljs codeblock` does not become a language.
````ruby
require "markbridge/html"
result = Markbridge.html_to_markdown('puts 1
')
result.markdown
# => "```ruby\nputs 1\n```"
````
## Parser characteristics
* **Uses Nokogiri’s HTML fragment parser** — handles malformed input without raising.
* **Stateless handlers** — simpler than BBCode’s open/close callback API. A handler is an object responding to `#process(element:, parent:)`.
```ruby
class AsideHandler < Markbridge::Parsers::HTML::Handlers::BaseHandler
def initialize
@element_class = AST::Quote
end
attr_reader :element_class
def process(element:, parent:)
note = AST::Quote.new
parent << note
note # return node to recurse into for children
end
end
handlers =
Markbridge::Parsers::HTML::HandlerRegistry.build_from_default do |registry|
registry.register("aside", AsideHandler.new)
end
Markbridge.html_to_markdown("", handlers:)
```
## Using the parser directly
```ruby
parser = Markbridge::Parsers::HTML::Parser.new
ast = parser.parse("rich content
")
renderer = Markbridge::Renderers::Discourse::Renderer.new
renderer.render(ast)
```
## What’s not supported
The default registry is intentionally scoped to the Discourse-facing subset. Notably:
* Inline styles and ``/`` without handlers pass through transparently (children only).
* `