User Rating 0.0
Total Usage 0 times
Input (Pug)
Output (HTML)
Quick Presets:
Is this tool helpful?

Your feedback helps us improve.

About

Template engines like Pug and HAML reduce markup verbosity through indentation-based nesting and shorthand syntax for classes (.), IDs (#), and attributes. A misplaced indent or forgotten closing structure can produce malformed HTML that breaks page rendering, accessibility trees, and SEO crawlers. This tool parses the abstract syntax of each engine and emits standards-compliant HTML with proper tag nesting. It also reverses the process: feed it HTML and receive valid Pug or HAML output. The parser handles self-closing void elements (img, br, hr, input), attribute lists, inline text content, pipe-based text blocks, and doctype declarations. Note: advanced features like mixins, includes, extends, filters, and embedded JavaScript evaluation are outside scope. The converter assumes static template content only.

pug to html jade to html haml to html template converter html converter pug converter haml converter template engine code converter

Formulas

Template engine conversion is a lexical and syntactic transformation rather than a mathematical function. The core process follows a deterministic pipeline:

Source Tokenize(lines) BuildTree(indent) Emit(HTML)

Each source line is decomposed into an AST node with properties:

Node = { tag, id, classes[], attrs{}, text, children[], depth }

Indentation depth d determines parent-child relationships. A line at depth d + 1 becomes a child of the nearest preceding line at depth d. The tree is walked depth-first to produce nested HTML with proper opening and closing tags.

For reverse conversion (HTML Template), the HTML string is parsed via the browser's native DOMParser API into a DOM tree. Each element node is visited recursively, extracting tagName, id, classList, and attributes, then formatting per the target engine's syntax rules at the correct indentation level.

Where tag = element name (e.g., div, p, a), id = element identifier, classes = array of CSS class names, attrs = key-value map of HTML attributes, text = inline text content, depth = nesting level determined by leading whitespace count divided by indent unit size (typically 2).

Reference Data

FeaturePug (Jade) SyntaxHAML SyntaxHTML Output
Tagdiv%div<div></div>
Tag with IDdiv#main%div#main<div id="main"></div>
Tag with classdiv.container%div.container<div class="container"></div>
Multiple classesdiv.foo.bar%div.foo.bar<div class="foo bar"></div>
ID + class shorthand#app.wrapper#app.wrapper<div id="app" class="wrapper"></div>
Attributesa(href="/", title="Home")%a{href: "/", title: "Home"}<a href="/" title="Home"></a>
Inline textp Hello world%p Hello world<p>Hello world</p>
Nested childrenIndent 2 spacesIndent 2 spacesNested tags
Self-closingimg(src="a.png")%img{src: "a.png"}/<img src="a.png" />
Doctype HTML5doctype html!!! 5<!DOCTYPE html>
Pipe text| Plain text linePlain text linePlain text line
HTML comment// comment/ comment<!-- comment -->
Void elementsbr, hr, input%br, %hr, %inputSelf-closing by spec
Boolean attributesinput(disabled)%input{disabled: true}<input disabled />
Data attributesdiv(data-id="5")%div{"data-id": "5"}<div data-id="5"></div>
Implicit div.box or #box.box or #box<div class="box"></div>
Block text (Pug)p. + indented linesN/A<p>text...</p>
Unescaped HTML (HAML)N/A!= <b>bold</b><b>bold</b>

Frequently Asked Questions

The parser calculates indentation depth per line by counting leading spaces. If a line jumps more than one level deeper than its predecessor (e.g., from depth 0 to depth 2 without an intermediate depth 1), the converter treats it as a child of the last node but flags inconsistent indentation in the output. Mixed tabs and spaces are normalized to spaces with a tab width of 2. For best results, use consistent 2-space indentation throughout.
This converter handles static template syntax: tags, IDs, classes, attributes, inline text, pipe text, block text, comments, doctypes, and self-closing void elements. It does not evaluate dynamic features such as mixins (mixin/+mixin), includes, extends, template inheritance, conditionals (if/else/unless), loops (each/while), inline JavaScript expressions, interpolated JavaScript (#{expr}), filters (:markdown, :coffee), and unbuffered code blocks. These features require a runtime execution environment that cannot be replicated with static parsing alone.
Yes. Set the direction to "HTML → Pug" or "HTML → HAML" using the direction toggle. The converter parses your HTML via the browser's native DOMParser, walks the resulting DOM tree, and emits properly indented template syntax. The output uses implicit div shorthand where applicable (e.g., a <div> with only a class becomes .classname). Note that the reverse conversion produces clean but opinionated output - attribute order may differ from your original template, and any inline styles or scripts are preserved as literal attributes.
HTML void elements (img, br, hr, input, meta, link, area, base, col, embed, source, track, wbr) are automatically detected by tag name. In HTML output, they render as self-closing (e.g., <img src="...">). In Pug output, they appear without explicit self-closing since Pug handles this automatically. In HAML output, they receive the trailing / marker per HAML convention. No closing tags are ever emitted for void elements regardless of conversion direction.
The parser accepts both Ruby symbol syntax ({class: "val"}) and string key syntax ({"class" => "val", "data-id" => "5"}). Symbol keys are converted to their string equivalents during parsing. The hashrocket (=>) syntax is also supported. However, actual Ruby expressions within attribute values (e.g., {class: @variable}) cannot be evaluated and will be output as literal strings.
Yes. The emitted HTML uses 2-space indentation for nested elements, with each opening tag on its own line. Inline text content appears on the same line as its parent tag for short content. This produces readable, well-formatted HTML suitable for direct use in production. You can adjust the output indent size is fixed at 2 spaces per depth level.