BBCode
BBCode is Markbridge’s most feature-rich input format. The default handler registry covers formatting, lists, tables, quotes, spoilers, images, attachments, sizing, color, alignment, and more.
Quick start
Section titled “Quick start”require "markbridge/bbcode"
bbcode = "[b]Hello[/b] [url=https://example.com]world[/url]!"result = Markbridge.bbcode_to_markdown(bbcode)result.markdown# => "**Hello** [world](https://example.com)!"result is a Markbridge::Conversion — .markdown is the rendered string, and the same object also exposes .unknown_tags, .diagnostics (auto-closed counts, depth-exceeded counts, unclosed raw-tag list), and .errors.
To get the AST instead of rendered Markdown:
parse = Markbridge.parse_bbcode(bbcode)parse.ast# => AST::Document(Bold("Hello"), Text(" "), Url("world", href: "..."))Supported tags
Section titled “Supported tags”All tag names are case-insensitive. Aliases in the same row use the same handler.
A few tags take variants:
- Code language —
[code=ruby]or[code lang=ruby]. - Ordered list —
[list=1](same as[ol]). - Quote attribution —
[quote="author, post:1, topic:2"]. - Link forms —
[url]also accepts[url=href]text[/url]and[url]href[/url];[email=addr]text[/email]and[img=src]alt[/img]follow the same shape. - Bare links — a
[url]whose text equals the href (or has no text) renders as the plain link, not[href](href), so Discourse autolinks and oneboxes it.
For the exact registration list, see HandlerRegistry.default.
Using the parser directly
Section titled “Using the parser directly”The bbcode_to_markdown convenience wraps parser + renderer. Calling them directly gives you the AST for inspection or custom rendering:
parser = Markbridge::Parsers::BBCode::Parser.newast = parser.parse("[b]bold[/b] with [unknown]mystery[/unknown]")
parser.unknown_tags# => {"unknown" => 2} # count of open + close tokens seen
renderer = Markbridge::Renderers::Discourse::Renderer.newrenderer.render(ast)# => "**bold** with mystery"For most callers, parse_bbcode is the better entry point — it returns a Parse object that already exposes .unknown_tags and .diagnostics without reaching for the parser instance.
Closing strategies
Section titled “Closing strategies”BBCode inputs from real forums often have mismatched or out-of-order tags. Markbridge ships with two strategies:
- Reordering (default) — reconciles sequences of up to 5 mismatched closing tags, e.g.
[b][i]text[/b][/i]→Bold(Italic("text")). - Strict — only auto-closes; won’t reorder. More predictable, more likely to reject input.
require "markbridge/bbcode"
handlers = Markbridge::Parsers::BBCode::HandlerRegistry.build_from_default do |registry| reconciler = Markbridge::Parsers::BBCode::ClosingStrategies::TagReconciler.new(registry:) registry.closing_strategy = Markbridge::Parsers::BBCode::ClosingStrategies::Strict.new(reconciler) end
Markbridge.bbcode_to_markdown("[b][i]text[/b][/i]", handlers:)Graceful degradation
Section titled “Graceful degradation”Unknown tags don’t raise. The wrapper is skipped; children are parsed normally:
Markbridge.bbcode_to_markdown("[unknown]inner text[/unknown]")# => "inner text"Unknown tag counts are surfaced on Conversion#unknown_tags (and Parse#unknown_tags) — no need to drop to the parser instance.
Limits
Section titled “Limits”- Max nesting depth: 100. Exceeding raises
MaxDepthExceededError. - Max auto-close depth: 5 levels — also bounds how deep
Reorderingwill look for a matching opener.
Customizing
Section titled “Customizing”Register a custom handler to recognize a new tag, or replace the built-in one:
handlers = Markbridge::Parsers::BBCode::HandlerRegistry.build_from_default do |registry| registry.register("callout", MyCalloutHandler.new) end
Markbridge.bbcode_to_markdown(input, handlers:)See Extending Markbridge for a full walkthrough, or Wrapping a default handler for HandlerRegistry#overlay — the cleanest way to delegate to the default for the cases your handler doesn’t need to change.