An Introduction to Haml

Haml is a markup language predominantly used with Ruby that cleanly and simply describes the HTML of any web document without the use of inline code. It is a popular alternative to using Rails templating language (.erb) and allows you to embed Ruby code into your markup.

It aims to reduce repetition in your markup by closing tags for you based on the structure of the indents in your code. The result is markup that is well-structured, DRY, logical, and easier to read.

This article is going to introduce you to writing your HTML as Haml.

It can be used in many Ruby frameworks, such as Rails and Sinatra, in Node.js, PHP and .NET.

You can also use Haml on a project independent of Ruby, by installing the Haml gem on your machine and using the command line to convert it to html.

Installing Haml

To use Haml you’ll first need to install it. This shouldn’t be any harder than opening up your command line and typing:

gem install haml

Noteworthy points while using HAML

  • Haml uses whitespace and indenting to format the HTML.
  • Tags are prefixed with a %. Closing tags aren’t required.
  • Haml assumes you are outputting a <div> tag unless you specify otherwise
  • id attributes are specified in the same way you write an id rule in CSS i.e. #container
  • You can also add class attributes to an element the same way you add an id attribute:

But what about other attributes that we will need to add to our markup? Things like lang, src, rel and href? Well that’s easily done using one of two methods:

  • You can use curly braces and specify your attributes with a Ruby hash. For example:

%img{ :src => "/path/to/image", :alt => "Description of image" }

Or you can use parentheses and use a more HTML-like foo=”bar” approach:

%img ( src="/path/to/image", alt="Description of image")

Both of these will output the following HTML:

<img src="/path/to/image" alt="Description of image">

Using this approach we can easily add CSS, JavaScript and any meta tags we need to our templates:

%meta{ :charset => "utf-8" } 
%link{ :rel => "stylesheet", :href => "/css/master.css" }

Will give us:

<meta charset="utf-8"> 
<link rel="stylesheet" href="/css/master.css">


%script{ :src => "/js/site.js" }

Will give us:

<script src="/js/site.js"></script>


Haml lets you add three types of comments to your markup:

  1. HTML comments
  2. Conditional comments
  3. Haml comments

HTML comments can be added using a forward slash ‘/’ but depending on where you place it will affect what gets wrapped in comments:

/ A forward slash at the start of a line wraps that line in a comment  
%p Roads? Where we're going we don't need roads

A forward slash at the start of a nested block wraps the whole block in a comment
%p Roads? Where we're going we don't need roads

Once compiled our output will be:

<!-- Only this line will be wrapped in a comment --> 
<p>Roads? Where we're going we don't need roads</p>
Now the whole block will be commented out
<p>Roads? Where we're going we don't need roads</p>

Conditional comments can be added by placing the condition in square brackets after the ‘/’:

/[if IE] %link { :rel => "stylesheet", :href => "/css/ie.css" }

This gives us the following HTML:

<!--[if IE]> <link href="/css/ie.css" rel="stylesheet"> <![endif]-->

Haml comments are comments that included in the template file but not rendered in the final output. You specify them with -# and the same rules that applied to HTML comments apply here too:

%p The line below won't appear in the HTML 
-# The rest of this line is a comment
%p The line above won't appear in the HTML, nor will the lines underneath
None of this nested text will appear
in our rendered output either

This produces:

<p>The line below won't appear in the HTML</p> 
<p>The line above won't appear in the HTML, nor will the lines underneath</p>

Adding Some Ruby Code

Whilst this article has focused on how you can write HTML using Haml, we couldn’t finish it without a brief bit on how to get some Ruby code into your template.

To insert some Ruby code, just add the '=' sign followed by the code. For example:


The code will be evaluated and output into the markup wrapped in

tags like so:

<p>Sat Aug 06 15:06:09 +0100 2011</p>

HAML Cheat Sheet


/ -------------------------------------------
/ Indenting
/ -------------------------------------------

Because of the importance indentation has on how your code is rendered, the indents should be consistent throughout the document. Any differences in indentation will throw an error. It's common-practice to use two spaces, but it's really up to you, as long as they're constant.

/ -------------------------------------------
/ Comments
/ -------------------------------------------

/ This is what a comment looks like in Haml.

To write a multi line comment, indent your commented code to be
wrapped by the forward slash

-# This is a silent comment, which means it won't be rendered into the doc at all

/ -------------------------------------------
/ Html elements
/ -------------------------------------------

/ To write your tags, use the percent sign followed by the name of the tag

/ Notice no closing tags. The above code would output

The div tag is the default element, so it can be omitted.
You can define only class/id using . or #
For example


/ Can be written

/ To add content to a tag, add the text directly after the declaration
%h1 Headline copy

/ To write multiline content, nest it instead
This is a lot of content that we could probably split onto two
separate lines.

You can escape html by using the ampersand and equals sign ( &= ). This converts html-sensitive characters (&, /, :) into their html encoded equivalents. For example

&= "Yes & yes"

/ would output 'Yes &amp; yes'

/ You can unescape html by using the bang and equals sign ( != )
!= "This is how you write a paragraph tag <p></p>"

/ which would output 'This is how you write a paragraph tag <p></p>'

/ CSS classes can be added to your tags either by chaining .classnames to the tag

/ or as part of a Ruby hash
%div{:class => 'foo bar'}

/ Attributes for any tag can be added in the hash
%a{:href => '#', :class => 'bar', :title => 'Bar'}

/ For boolean attributes assign the value 'true'
%input{:selected => true}

/ To write data-attributes, use the :data key with its value as another hash
%div{:data => {:attribute => 'foo'}}

/ For Ruby version 1.9 or higher you can use Ruby's new hash syntax
%div{ data: { attribute: 'foo' } }

/ Also you can use HTML-style attribute syntax.
%a(href='#' title='bar')

/ And both syntaxes together
%a(href='#'){ title: @my_class.title }

/ -------------------------------------------
/ Inserting Ruby
/ -------------------------------------------

To output a Ruby value as the contents of a tag, use an equals sign followed by the Ruby code


= book.publisher

/ To run some Ruby code without rendering it to the html, use a hyphen instead
- books = ['book 1', 'book 2', 'book 3']

/ Allowing you to do all sorts of awesome, like Ruby blocks
- books.shuffle.each_with_index do |book, index|
%h1= book

- if book do
%p This is a book

/ Adding ordered / unordered list

Again, no need to add the closing tags to the block, even for the Ruby. Indentation will take care of that for you.

/ -------------------------------------------
/ Inserting Table with bootstrap classes
/ -------------------------------------------

%th Header 1
%th Header 2

%td Value1
%td value2

Foot value

/ -------------------------------------------
/ Inline Ruby / Ruby interpolation
/ -------------------------------------------

/ Include a Ruby variable in a line of plain text using #{}
%p Your highest scoring game is #{best_game}

/ -------------------------------------------
/ Filters
/ -------------------------------------------

Filters pass the block to another filtering program and return the result in Haml To use a filter, type a colon and the name of the filter

/ Markdown filter
# Header

Text **inside** the *block*

/ The code above is compiled into

<p>Text <strong>inside</strong> the <em>block</em></p>

/ Javascript filter
console.log('This is inline <script>');

/ is compiled into
console.log('This is inline <script>');

There are many types of filters (:markdown, :javascript, :coffee, :css, :ruby and so on)
Also you can define your own filters using Haml::Filters

Experience with Front-end Technologies and MERN / MEAN Stack. Working on all Major UI Frameworks like React, Angular.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store