HTML to HAML Converter
Convert HTML markup to HAML template syntax — no closing tags, indentation-based nesting.
What is HAML and how does conversion work?
HAML (HTML Abstraction Markup Language) is an indentation-based template language popular in Ruby on Rails applications. It replaces verbose HTML with concise shorthand: %div for a div, #id for IDs, .class for classes, and no closing tags — indentation defines nesting. This converter handles the most common patterns including nested elements, attributes, IDs, and classes.
For Node.js templates, try the HTML to Pug Converter. For JSX/React, use HTML to JSX.
Built and maintained by Meet Shah · Last updated
What this tool is used for
- Migrating a template from HTML into HAML.
- Converting designer markup into the syntax a Rails project uses.
- Learning HAML's shorthand by seeing your own markup translated.
- Producing a starting template you then add Ruby interpolation to.
- Converting a Rails partial into the syntax the rest of the views use.
How it works in practice
A worked example
A Rails developer is moving a hand-written order card from an HTML mock-up into a Haml partial and wants the tags, ids and classes converted rather than retyped.
<div class="order-card" id="order-1042"> <h2 class="order-card__title">Order 1042</h2> <p>Shipped to <a href="/orders/1042/track">Leeds</a> on Monday.</p> <button type="button" class="btn btn-primary" data-order-id="1042">Track parcel</button> </div>
#order-1042.order-card
%h2.order-card__title
Order 1042
%p
Shipped to
%a{ href: "/orders/1042/track" }
Leeds
on Monday.
%button.btn.btn-primary{ type: "button", "data-order-id": "1042" }
Track parcelThe div has vanished into its own selector: Haml assumes a div whenever a line starts with an id or a class, so the wrapper becomes #order-1042.order-card, and the button's two classes become two dotted names. Closing tags are gone because indentation now says where each element ends, and every run of text moves onto its own line one level deeper, including the words either side of the link, which is why one sentence now spans four lines. The data attribute is the one that needed care. The braces hold a Ruby hash, and a bare Ruby key cannot contain a hyphen, so type stays a plain key while data-order-id is written as a quoted one, "data-order-id": "1042", which Haml renders back as the same attribute.
The edge case that catches people
In Haml the first character of a line can be an instruction, so text that begins with one is escaped on the way out. A list item reading .NET 8 support comes out as \.NET 8 support, because an unescaped line starting with a dot is a div with the class NET; #1 in reviews becomes \#1 in reviews, and text opening with -, = or % gets the same leading backslash, which Haml removes when it renders the page. Ruby interpolation is neutralised the same way wherever it appears: Total: #{price} arrives as Total: \#{price}, so the page prints it rather than running it. Ordinary sentences come through untouched, because the backslash is added only where Haml would otherwise misread the line.
When not to use this tool
Not for templates that already contain ERB. An ERB tag such as <%= @user.name %> loses its opening bracket and arrives as the plain-text line \%= @user.name %>, where the html2haml gem parses both languages and is the better starting point. It also reads tags literally rather than as a browser does, so markup that leans on implied end tags, such as list items or paragraphs left unclosed, comes out with each one nested inside the one before. And the bodies of script and style elements arrive as plain text lines under %script and %style, with their indentation flattened, rather than inside Haml's :javascript and :css filters; move them into a filter, or out to an asset file, before you edit them in the template.
Frequently Asked Questions
- What is Haml's core idea?
- Indentation replaces closing tags entirely, and CSS-style selectors replace attributes: %div.card becomes <div class="card">, and .card alone implies a div. Nesting is expressed purely by whitespace.
- Which ecosystem is it from?
- Ruby, and Rails in particular — it predates most alternatives and remains common there. That heritage shows in the syntax, which embeds Ruby expressions with = and runs statements with -.
- How is inline content handled?
- This is Haml's known weak point. Long inline text with nested tags becomes awkward, and the succeed/precede helpers exist specifically to control whitespace around inline elements — a common source of frustration.
- Does conversion preserve whitespace exactly?
- Not always, and it matters for inline elements where a space between tags is significant. Haml offers whitespace-removal operators (> and <) precisely because indentation-based templates cannot express spacing implicitly.
- Should I use Haml for a new project?
- Only in a Ruby codebase that already does. Rails' default is ERB, and outside Ruby there is little tooling. The indentation approach also fights against IDE support and against pasting plain HTML from designers.
- What does Haml do about whitespace-sensitive elements?
- It provides the
~operator andpreservehelper, because Haml's own indentation would otherwise be inserted into a<pre>block. Converting such content without them changes what the page displays.
Common errors and gotchas
- Losing significant whitespace between inline elements, which HAML handles differently and visibly.
- Mixing tabs and spaces, which HAML rejects rather than tolerating.
- Converting markup containing ERB, which HAML treats as text rather than code.
- Assuming attribute syntax converts cleanly, since HAML offers two forms with different rules.
- Expecting indentation to be flexible, when one space changes the structure.