HTML: Source version: Markbridge 0.4.2. These docs are built from the repository and may include unreleased changes. # HTML > Convert HTML into Discourse-flavored Markdown using Nokogiri. The HTML parser uses Nokogiri to tolerate malformed HTML and produces the same AST the other parsers feed into. ## Requirements Add `nokogiri` to your Gemfile. It’s a runtime dependency for the HTML parser: ```ruby gem "nokogiri" ``` ## Quick start ```ruby require "markbridge/html" result = Markbridge.html_to_markdown("

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` | | ``, ``, `` | `~~strike~~` | `AST::Strikethrough` | | `` | `underline` | `AST::Underline` | | ``, `` | `` / `` | `AST::Superscript`, `AST::Subscript` | | ``, `` | 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` | | `` | `![](src)` | `AST::Image` | | `
` | `[quote]…[/quote]` | `AST::Quote` | | `
    `, `
      ` | `- item` / `1. item` | `AST::List` | | `
    1. ` | List item | `AST::ListItem` | | ``, ``, ``, ``, `` 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). * `
      `, `` | GFM table | `AST::Table` | | `
      ` | Hard line break | `AST::LineBreak` | | `
      ` | `---` | `AST::HorizontalRule` | | `

      ` | Paragraph spacing | — (transparent) | `