Your comprehensive guide for Twig front-end view templates.
Read more
This post is an iteration on ERB and Twig Cross-Reference for Front-End Development. That post is geared towards developers who want to translate their Twig knowledge to ERB, or vice versa. You may also be interested in Fundamental Twig for Front-End Development.
Contents
ERB (Embedded Ruby) is a feature of Ruby that lets you —you guessed it!— embed Ruby in other files. ERB files have the extension .<compiled_extension>.erb. It is the language HAML and Slim are shorthand for. ERB is commonly used for templating Views in Rails apps.
Because it can do anything Ruby can do, it’s extremely powerful, has a steeper learning curve than languages intended for front-end templates specifically, and can do a lot that isn’t relevant to front-end templating. There’s no cannonical ERB-for-front-end-developers documentation, and the Rails official documentation is immense and hard to dig through. Some resources if for learning ERB:
link... and button_to methods are essential.content tag and tag methods are useful.link_to<%# … %>
erb<%# comment %>
erb<%# comment %>
=begin…=end
the opening and closing tags must be at the start of the line
erb<%=begin %>block comment(both lines of both the begin and end tags must be at the start of their lines)<%=end %>
erb<%=begin %>block comment(both lines of both the begin and end tags must be at the start of their lines)<%=end %>
not
erb<%=begin %>not a comment<%=end %>
erb<%=begin %>not a comment<%=end %>
<%= … %>
erb<%= "print this" %> <%# output: `"print this"` %><%= 1 + 2 %> <%# output: `3` %>
erb<%= "print this" %> <%# output: `"print this"` %><%= 1 + 2 %> <%# output: `3` %>
<% … %>
erb<% if … do %> … <% end %>
erb<% if … do %> … <% end %>
if and unless
erb<%= 2 if true %> <%# output: `2` %><%= 2 if false %> <%# output: `nil` %><%= 2 unless true %> <%# output: `nil` %><%= 2 unless false %> <%# output: `2` %>
erb<%= 2 if true %> <%# output: `2` %><%= 2 if false %> <%# output: `nil` %><%= 2 unless true %> <%# output: `nil` %><%= 2 unless false %> <%# output: `2` %>
if…elsif…end
erb<%# assuming x, y, z, and n are defined %><% if x %>y<% elsif z == n %> <%# note the spelling of elsif %>0<% else %>1<% end %>
erb<%# assuming x, y, z, and n are defined %><% if x %>y<% elsif z == n %> <%# note the spelling of elsif %>0<% else %>1<% end %>
ERB supports “condition ? iftrue : iffalse”, and “ifselftrue ?: otherwise”.
Note that the “then” case : must be provided
erb<%# assuming x, y, z, and n are defined %><%# if x then y %><%# omitting the "else" will throw an error #><%= x ? y : '' %><%# if x is true, y. otherwise, if z equals n then 0. otherwise 1 %><%= x ? y : z == n ? 0 : 1 %><%# ternary operator: x if x is true, otherwise y %><%= x ?: y %>
erb<%# assuming x, y, z, and n are defined %><%# if x then y %><%# omitting the "else" will throw an error #><%= x ? y : '' %><%# if x is true, y. otherwise, if z equals n then 0. otherwise 1 %><%= x ? y : z == n ? 0 : 1 %><%# ternary operator: x if x is true, otherwise y %><%= x ?: y %>
0 is True in Boolean contexts
erb<%= false ? 'truthy' : 'falsy' %> <%# output: `"falsy"` %><%= 0 ? 'truthy' : 'falsy' %> <%# output: `"truthy"` %>
erb<%= false ? 'truthy' : 'falsy' %> <%# output: `"falsy"` %><%= 0 ? 'truthy' : 'falsy' %> <%# output: `"truthy"` %>
=
erb<% var = 1 %><% anotherVar = 0 %><% falseVar = false %><%= 2 if var %> <%# output: `2` %><%= 2 if anotherVar %> <%# output: `2` %><%= 2 if falseVar %> <%# output: `` %><%= 2 unless falseVar %> <%# output: `2` %>
erb<% var = 1 %><% anotherVar = 0 %><% falseVar = false %><%= 2 if var %> <%# output: `2` %><%= 2 if anotherVar %> <%# output: `2` %><%= 2 if falseVar %> <%# output: `` %><%= 2 unless falseVar %> <%# output: `2` %>
Multi-line blocks of markup can stored in an identifier with content_for x do…end
erb<% content_for longVar do %><div>…</div><% end %><%= content_for(longVar) %>
erb<% content_for longVar do %><div>…</div><% end %><%= content_for(longVar) %>
Note: content_for is additive: each time you provide content for a given variable, that content is appeneded to what was there already. To use content_for to overwrite a global variable, use the flush: true option:
erb<% content_for refreshedVar do %>a<% end %><% content_for refreshedVar, flush: true do %>b<% end %>
erb<% content_for refreshedVar do %>a<% end %><% content_for refreshedVar, flush: true do %>b<% end %>
defined?()
erb<%# output: the content if `var` is defined %><% if defined?(var) %>…<% end %><%# output: `var` if `var` is defined, otherwise `fallback` %><%= defined?(var) ? var : fallback %>
erb<%# output: the content if `var` is defined %><% if defined?(var) %>…<% end %><%# output: `var` if `var` is defined, otherwise `fallback` %><%= defined?(var) ? var : fallback %>
||=, the OR Equal operator
erb<%# output: `var` if it is defined and not nil and not false, otherwise `fallback` %><% var ||= fallback %><%=begin %> common front-end use cases:1. output a variable only if it is defined<%=end %><% var ||= nil %><%# set a variable with a fallback %><% x = y ||= nil %>
erb<%# output: `var` if it is defined and not nil and not false, otherwise `fallback` %><% var ||= fallback %><%=begin %> common front-end use cases:1. output a variable only if it is defined<%=end %><% var ||= nil %><%# set a variable with a fallback %><% x = y ||= nil %>
#{var}
erb<% x = 1 %><%= "this is interpolated: #{x}" %><%# output: `this is interpolated: 1` %>
erb<% x = 1 %><%= "this is interpolated: #{x}" %><%# output: `this is interpolated: 1` %>
+ (plus). Note that to concatenate a string and a number in Ruby, the number must be converted to a string.
erb<% string_variable = 'world' %><% number_variable = 2 %><%= 'hello ' + string_variable %> <%# output: `"hello world"` %><%= "example #{number_variable}" %> <%# output: `"example 2"` %><%= 'example ' + 3.to_s %> <%# output: `"example 3"` %>
erb<% string_variable = 'world' %><% number_variable = 2 %><%= 'hello ' + string_variable %> <%# output: `"hello world"` %><%= "example #{number_variable}" %> <%# output: `"example 2"` %><%= 'example ' + 3.to_s %> <%# output: `"example 3"` %>
n.each do |i|…end
erb<% items = ['a', 'b', 'c'] %><%# output: `...` %><% [0..items.length].each do %>.<% end %><%# output: `a b c ` %><% items.each do |item| %><%= item %><% end %>
erb<% items = ['a', 'b', 'c'] %><%# output: `...` %><% [0..items.length].each do %>.<% end %><%# output: `a b c ` %><% items.each do |item| %><%= item %><% end %>
n.each_with_index do |i, index|…end
erb<%# output: `0. a 1. b 2. c ` %><% items = ['a', 'b', 'c'] %><% items.each_with_index do |item,index| %><%= index %>. <%= item %><% end %>
erb<%# output: `0. a 1. b 2. c ` %><% items = ['a', 'b', 'c'] %><% items.each_with_index do |item,index| %><%= index %>. <%= item %><% end %>
n.times do |i|…end
erb<%# output: `0 1 2 3 4 5 6 7 8 9` %><% 10.times do |i| %><%= i %> <% end %>
erb<%# output: `0 1 2 3 4 5 6 7 8 9` %><% 10.times do |i| %><%= i %> <% end %>
.each_with_index’s index is always 0-indexed, so add 1
erb<% items.each_with_index do |item,index| %><%= index + 1 %>. <%= item %><% end %>
erb<% items.each_with_index do |item,index| %><%= index + 1 %>. <%= item %><% end %>
n.times do |i|…end
erb<%# output: `1 2 3 4 5 6 7 8 9 10 ` %><% 10.times do |i| %><%= i %> <% end %>
erb<%# output: `1 2 3 4 5 6 7 8 9 10 ` %><% 10.times do |i| %><%= i %> <% end %>
n.times do |i|…end
erb<% n = 3 %><%# output: `...` %><% n.times do %>.<% end %><%# output: `1 2 3 ` %><% n.times do |i| %><%= i %><% end %>
erb<% n = 3 %><%# output: `...` %><% n.times do %>.<% end %><%# output: `1 2 3 ` %><% n.times do |i| %><%= i %><% end %>
There are several options for formatting an object’s data, notably: simply outputting, .inspecting, and debug()ing. For basic data-checking purposes in a view, the essential difference is debug() returns YAML while inspect and printing return strings.
erb<%# for some object `posts` %><%= posts %><%= posts.inspect %><%= debug(posts) %>
erb<%# for some object `posts` %><%= posts %><%= posts.inspect %><%= debug(posts) %>
.slice(index), .slice(start,count)
erb<%= [1,2,3,4].slice(1) %> <%# output: `2` %><%= [1,2,3,4].slice(1,2) %> <%# output: `[2,3]` %>
erb<%= [1,2,3,4].slice(1) %> <%# output: `2` %><%= [1,2,3,4].slice(1,2) %> <%# output: `[2,3]` %>
count items.take(count) or .first(count)
erb<%= [1,2,3,4].take(2) %> <%# output: `[1,2]` %><%= [1,2,3,4].first(2) %> <%# output: `[1,2]` %>
erb<%= [1,2,3,4].take(2) %> <%# output: `[1,2]` %><%= [1,2,3,4].first(2) %> <%# output: `[1,2]` %>
If trim_mode is set to -, a - in the closing erb tag will trim trailing whitespace:
erb<% something -%>1<%= something_else -%>2<% another_thing %>
erb<% something -%>1<%= something_else -%>2<% another_thing %>
is equivalent to
erb<% something %>1<%= something_else %>2<% another_thing %>
erb<% something %>1<%= something_else %>2<% another_thing %>
Use a Symbol :property to look up an operation on a Hash:
erb<% myHash = {hello: 'world'} %><%= myHash[:hello] %> <%# output: "world" %>
erb<% myHash = {hello: 'world'} %><%= myHash[:hello] %> <%# output: "world" %>
For a layout file that pulls in page: content_for in child, yield in parent
layouts/layout.html.erb
erb<%= yield :myBlock %>
erb<%= yield :myBlock %>
views/page.html.erb
erb<% content_for :myBlock do %>the content<% end %>
erb<% content_for :myBlock do %>the content<% end %>
layouts/layout.html.erb
erb<% if content_for?(:my_content) %><%= yield :my_content %><% else %>default content<% end %>
erb<% if content_for?(:my_content) %><%= yield :my_content %><% else %>default content<% end %>
views/page.html.erb
erb<% content_for :my_content do %>the content<% end %>
erb<% content_for :my_content do %>the content<% end %>
render will output the contents of another file
erb<%= render 'path/to/x' %>
erb<%= render 'path/to/x' %>
To pass values to the rendered file, define them:
erb<% a = 1 %><% b = 2 %><%= render 'path/to/x', a:a, b:b %> <%# in path/to/x a=1 and b=2 %>
erb<% a = 1 %><% b = 2 %><%= render 'path/to/x', a:a, b:b %> <%# in path/to/x a=1 and b=2 %>
If the rendered file expects different variable names, use those:
erb<% a = 1 %><% b = 2 %><%= render 'path/to/x', y:a, z:b %> <%# in path/to/x y=1 and z=2 %>
erb<% a = 1 %><% b = 2 %><%= render 'path/to/x', y:a, z:b %> <%# in path/to/x y=1 and z=2 %>
Fundamental Twig for Front-End Development
Your comprehensive guide for Twig front-end view templates.
Watch for specific added nodes with MutationObserver
MutationObserver makes it easy to watch for the addition of specific nodes, if you know where to drill.
Numbered Code Block Lines in Eleventy with Shiki Twoslash
Bringing in a third-party library for easy, reliable line numbering