FormatterHQ

Handlebars / Glimmer Formatter

Format Handlebars and Ember Glimmer templates: block helpers, angle-bracket components, @arguments and {{on}} modifiers are laid out consistently.

Input HANDLEBARS
Output HANDLEBARS
Ready.

How to use the Handlebars / Glimmer Formatter

  1. Paste your Handlebars or Glimmer template (.hbs) into the Input editor, or use Sample, Upload file or Load URL.
  2. Choose Indent and Line width.
  3. Press Format to reprint the template with Prettier’s Glimmer parser.
  4. Use Copy or Download above the output panel to take the formatted template with you.

A Handlebars formatter based on the Glimmer parser

This Handlebars formatter uses Prettier's glimmer parser, the template parser from Ember's Glimmer rendering engine. Glimmer templates are a superset of Handlebars: they add angle-bracket components (<UserCard @user={{this.user}} />), named arguments with @, and element modifiers such as {{on "click" this.save}}. Classic Handlebars templates used with Handlebars.js or Express view engines are parsed by the same grammar, as long as they only use standard mustache and block syntax. Paste the contents of an .hbs or .handlebars file directly.

Example

<ul class="todo-list">{{#each @todos key="id" as |todo|}}<li class="{{if todo.done 'done'}}"><Input @type="checkbox" @checked={{todo.done}} {{on "change" (fn this.toggle todo)}} />{{todo.title}}</li>{{else}}<li>Nothing to do</li>{{/each}}</ul>
<ul class="todo-list">{{#each @todos key="id" as |todo|}}<li
      class="{{if todo.done 'done'}}"
    ><Input
        @type="checkbox"
        @checked={{todo.done}}
        {{on "change" (fn this.toggle todo)}}
      />{{todo.title}}</li>{{else}}<li>Nothing to do</li>{{/each}}</ul>

Because the input had no whitespace between tags and mustaches, the formatter keeps them touching and only wraps the long element's attributes. Whitespace in Handlebars output is visible to users, so Prettier will not invent it. Write your source with line breaks between block helpers and elements, and the formatter indents each level properly.

What gets formatted

  • Block helpers: {{#if}}, {{else if}}, {{#each}} with block params, {{#let}}, {{#unless}}.
  • Components and their @arguments, one per line once they exceed the line width.
  • Sub-expressions like (fn this.toggle todo) and hash arguments like key="id".
  • Comments in both forms, {{! short }} and {{!-- long --}}.

Matching your project's Prettier settings

Prettier picks the glimmer parser automatically for .hbs and .handlebars files, so an Ember or Handlebars project that already runs npx prettier --write "app/**/*.hbs" uses the same printer as this page. To get identical output, set Indent and Line width here to the tabWidth and printWidth from your .prettierrc; otherwise the next commit hook will reformat what you pasted.

Line width decides where wrapping starts. An element whose tag and attributes fit on one line stays on one line; once it is longer, each attribute, @argument and modifier moves to its own line, as in the example above. Formatting is only about layout, so pair it with a linter such as ember-template-lint if you also want rules about accessibility or deprecated syntax.

Handlebars and Glimmer syntax at a glance

SyntaxMeaning
{{title}}Output a value, HTML-escaped
{{{html}}}Output raw, unescaped HTML
{{this.count}} / {{@count}}Glimmer: component property vs. argument passed in
{{~#if a~}}Tilde strips whitespace on that side of the mustache
{{!-- note --}}Comment that may contain }}

The formatter keeps tildes and comment styles exactly as written, so whitespace control in your output does not change.

Common parse errors

  • Unclosed blocks: every {{#each}} needs a matching {{/each}}.
  • Partials ({{> header}}) are Handlebars.js features that Glimmer does not support, so templates using them fail to parse. Format those files with the HTML Formatter instead.
  • Triple-stash {{{html}}} is supported, but be careful: it outputs unescaped HTML.

Ember component classes are JavaScript or TypeScript; format them with JavaScript Pretty Print. Templates are processed locally in your browser.

Frequently asked questions

Can I format plain Handlebars.js templates?
Yes, as long as they use standard mustaches and block helpers. Handlebars-only features such as partials and decorators are not part of the Glimmer grammar and cause a parse error.
Why didn’t the formatter add line breaks between my elements?
Whitespace between tags and mustaches is rendered in the page. If your template has none, Prettier keeps it that way and breaks lines inside tags instead so the output looks the same.
Does it support Ember’s template tag format (.gjs/.gts)?
No. Files that mix JavaScript and template tags need a Prettier plugin for template imports. Paste only the template markup here.
Which quote style is used for attributes?
Attributes are printed with double quotes. A string literal inside a mustache that sits within a double-quoted attribute uses single quotes to avoid escaping, as in class="{{if done 'done'}}".

Last updated September 26, 2026

Related tools