Loops

Iterate over arrays and collections to dynamically generate content in your templates.

Experimental Feature: Loops are currently experimental. The syntax and behavior may change in future versions. Use with caution and check for updates.

Introduction

Hammer's loop feature allows you to iterate over arrays and collections, generating content for each item. This enables you to create dynamic lists, grids, and repeated content without writing repetitive code.

Loops help you:

  • Generate content from arrays and collections
  • Create dynamic lists and grids
  • Avoid repetitive HTML code
  • Build flexible, data-driven templates

Basic Loops

Use @loop to iterate over an array or collection:

<!-- @var items = ["Apple", "Banana", "Cherry"] -->
<!-- @loop item in items -->
<div><!-- @item --></div>
<!-- @endloop -->

The content between @loop and @endloop will be rendered once for each item in the collection.

Tip: The variable name after in (e.g., item) is used to reference the current item in the loop. You can use any variable name you prefer.

Accessing Item Properties

When looping over objects, you can access properties using dot notation:

<!-- @var products = [{name: "Widget", price: 10}, {name: "Gadget", price: 20}] -->
<!-- @loop product in products -->
<div class="product">
    <h3><!-- @product.name --></h3>
    <p>$<!-- @product.price --></p>
</div>
<!-- @endloop -->

This allows you to create rich, dynamic content from structured data.

Combining with Conditionals

Loops can be combined with conditionals to create more complex logic. For example, you can check if a collection is empty before looping:

<!-- @var items = [{name: "Item 1"}, {name: "Item 2"}] -->
<!-- @unless items.empty? -->
    <!-- @loop item in items -->
    <div class="item"><!-- @item.name --></div>
    <!-- @endloop -->
<!-- @endunless -->

This ensures the loop only runs when there are items to display.

Conditional Inside Loop

You can also use conditionals inside loops to customize output for each item:

<!-- @loop product in products -->
    <!-- @if product.featured -->
    <div class="product featured">
        <span>Featured!</span>
        <h3><!-- @product.name --></h3>
    </div>
    <!-- @else -->
    <div class="product">
        <h3><!-- @product.name --></h3>
    </div>
    <!-- @endif -->
<!-- @endloop -->

Examples

Simple List

<!-- @var tags = ["HTML", "CSS", "JavaScript"] -->
<ul>
    <!-- @loop tag in tags -->
    <li><!-- @tag --></li>
    <!-- @endloop -->
</ul>

Product Grid

<div class="products-grid">
    <!-- @loop product in products -->
    <div class="product-card">
        <img src="<!-- @path @@product.image -->" alt="<!-- @product.name -->">
        <h3><!-- @product.name --></h3>
        <p><!-- @product.description --></p>
        <span class="price">$<!-- @product.price --></span>
    </div>
    <!-- @endloop -->
</div>

With Empty Check

<!-- @var posts = [] -->
<!-- @if posts.empty? -->
<p>No posts available.</p>
<!-- @else -->
    <!-- @loop post in posts -->
    <article>
        <h2><!-- @post.title --></h2>
        <p><!-- @post.excerpt --></p>
    </article>
    <!-- @endloop -->
<!-- @endif -->

Sorting & Ordering

You can control the order of items in a loop using the sort attribute directly on the loop tag.

Basic Sort

Add a sort attribute with a field name and direction:

<!-- @loop post in collections.posts sort="date:desc" -->
<article>
    <h2><!-- @post.title --></h2>
    <p><!-- @post.excerpt --></p>
</article>
<!-- @endloop -->

Sort Format

The format is field:direction:

  • asc or ascending — lowest to highest (A–Z, oldest first)
  • desc or descending — highest to lowest (Z–A, newest first)
  • If no direction is given, the default is asc

Multiple Sort Fields

Sort by multiple fields using comma-separated values. The first field is the primary sort:

<!-- @loop post in collections.posts sort="date:desc,title:asc" -->
<article>
    <h2><!-- @post.title --></h2>
</article>
<!-- @endloop -->

In this example, posts are sorted by date (newest first), and posts with the same date are then sorted alphabetically by title.

Supported Field Types

Sorting works with any field type:

  • Dates — ISO 8601 date values (e.g. 2026-03-01)
  • Numbers — numeric comparison
  • Strings — alphabetical (lexicographic) order
Tip: For blog posts, use sort="date:desc" to show the most recent posts first. For documentation, try sort="order:asc" with a numeric order field in your front matter.

Best Practices

Loop Structure

  • Always close loops with @endloop
  • Use descriptive variable names for loop items (e.g., product, post)
  • Keep loop content focused and readable
  • Avoid deeply nested loops when possible

Data Structure

  • Define arrays and objects clearly at the top of your file
  • Use consistent data structures across your project
  • Ensure array data is properly formatted
  • Document complex data structures

Combining with Conditionals

  • Check for empty arrays before looping when appropriate
  • Use conditionals inside loops to customize output
  • Keep conditional logic within loops simple and readable
  • Test loops with empty and populated data

Next Steps

Now that you understand loops, learn about: