HTML to Jade Converter
Convert HTML to Jade (Pug) syntax online with Meteor Handlebars support. Handles {{#if}}, {{#each}}, {{else}} blocks with proper 2-space indentation.
About
Jade (now Pug) eliminates closing tags, angle brackets, and attribute quoting through whitespace-significant syntax. Manual conversion introduces indentation errors that silently break template rendering. A single misplaced indent shifts an element's parent, changing DOM structure without any compiler warning. This tool parses raw HTML into an abstract syntax tree, then emits correct Jade output with consistent 2-space indentation. It preserves Meteor Handlebars block helpers ({{#if}}, {{#each}}, {{else}}, {{/if}}) as Jade mixin-style blocks, maintaining logical nesting that hand-conversion frequently corrupts.
The converter handles void elements (br, hr, img, input), boolean attributes, inline text vs. block text, class/id shorthand extraction, and multi-attribute formatting. It does not validate your HTML. Malformed input (unclosed tags, overlapping elements) produces best-effort output. For production Meteor templates, always verify the converted Jade renders identically in your Blaze engine before deploying.
Formulas
The converter operates as a three-stage pipeline: Tokenize, Parse, Emit.
Indentation at each depth level is computed as:
Where depth = 0 for root elements and increments by 1 for each nested child. Class shorthand extraction follows the pattern: if a tag has class and/or id attributes, they are extracted into dot/hash notation and removed from the attribute list. The remaining attributes are formatted as comma-separated key="value" pairs inside parentheses.
Handlebars block detection uses the regex pattern:
Where blockOpen captures the helper name and its arguments. The parser pushes a block node onto the stack, collects children until the matching blockClose, and pops. An {{else}} token splits the block's children into a consequent array and an alternate array.
Reference Data
| HTML Syntax | Jade/Pug Equivalent | Notes |
|---|---|---|
| <div></div> | div | Plain tag, no closing needed |
| <div class="box"> | div.box | Class shorthand with dot notation |
| <div id="main"> | div#main | ID shorthand with hash notation |
| <div id="app" class="container wide"> | div#app.container.wide | Combined ID and multiple classes |
| <input type="text" required> | input(type="text", required) | Attributes in parentheses, boolean attrs |
| <a href="/">Home</a> | a(href="/") Home | Inline text after tag |
| <p>Line 1<br>Line 2</p> | p | Line 1 br | Line 2 | Mixed content uses pipe for text |
| <!-- comment --> | // comment | Jade comment syntax |
| <!DOCTYPE html> | doctype html | Doctype declaration |
| {{#if isAdmin}} | +if isAdmin | Meteor Handlebars block open |
| {{else}} | +else | Handlebars else branch |
| {{/if}} | (indentation closes block) | No explicit close in Jade |
| {{#each items}} | +each items | Handlebars each loop |
| {{title}} | = title or #{title} | Expression interpolation |
| {{> header}} | +header | Partial inclusion |
| <div class="a"><span>X</span></div> | div.a span X | 2-space nested indentation |
| <img src="x.png" alt=""> | img(src="x.png", alt="") | Self-closing / void element |
| <script>...</script> | script. (content indented) | Dot suffix for raw block content |
| <style>...</style> | style. (content indented) | Dot suffix for raw block content |
Frequently Asked Questions
Hello world!
becomes p with children | Hello, strong world, and | ! each on separate indented lines.