# Whitespace Control Guide
Master whitespace handling in templates.
## The Problem
Templates often have unwanted whitespace in the output:
```
{% for item in items %}
Item: {{ item }}
{% endfor %}
```
This produces:
```
Item: 1
Item: 2
Item: 3
```
Notice the extra newlines and spaces. Whitespace control lets you remove them.
## Whitespace Modifiers
Use `-` at the start or end of tags to trim whitespace.
### Trim Left (Left Dash)
```
{{- expression }}
{%- tag %}
```
The dash removes whitespace to the left:
```
Text {{- "value" }}
```
Renders as: `Textvalue` (no space before value)
### Trim Right (Right Dash)
```
{{ expression -}}
{% tag -%}
```
The dash removes whitespace to the right:
```
{{ "value" -}} Text
```
Renders as: `valueText` (no space after value)
### Trim Both
```
{{- expression -}}
{%- tag -%}
```
Removes whitespace on both sides:
```
Text {{- "value" -}} More
```
Renders as: `TextvalueMore`
## Common Use Cases
### Removing Loop Newlines
**Without whitespace control:**
```
{% for item in items %}
{{ item }}
{% endfor %}
```
Output:
```
Item1
Item2
Item3
```
**With whitespace control:**
```
{%- for item in items -%}
{{ item }}
{%- endfor -%}
```
Output:
```
Item1 Item2 Item3
```
Or with newlines but no extra indentation:
```
{% for item in items -%}
{{ item }}
{% endfor -%}
```
Output:
```
Item1
Item2
Item3
```
### Clean HTML Generation
**Without whitespace control:**
```
<ul>
{% for item in items %}
<li>{{ item }}</li>
{% endfor %}
</ul>
```
Output:
```html
<ul>
<li>Item1</li>
<li>Item2</li>
</ul>
```
**With whitespace control:**
```
<ul>
{%- for item in items %}
<li>{{ item }}</li>
{%- endfor %}
</ul>
```
Output:
```html
<ul>
<li>Item1</li>
<li>Item2</li>
</ul>
```
### Conditional Text
```
Status: {% if active -%}Active{%- else -%}Inactive{%- endif %}
```
Without trim, this would have spaces: `Status: Active` or `Status: Inactive`
With trim: `Status: Active` or `Status: Inactive`
### Joining Items
Create a comma-separated list:
```
{% for item in items -%}
{{ item }}{{ if not forloop.last -%}}, {% endif -%}}
{%- endfor %}
```
This produces: `Item1, Item2, Item3` without trailing comma.
## Whitespace Breakdown
### Where Whitespace Appears
Whitespace includes:
- **Spaces** (` `)
- **Tabs** (`\t`)
- **Newlines** (`\n`)
- **Carriage returns** (`\r`)
### Whitespace Around Tags
```
before text
{% if condition %}
content
{% endif %}
after text
```
The dashes control whitespace adjacent to tags:
```
before text{%- if condition %}content{%- endif -%}after text
```
## Advanced Patterns
### CSV Generation
```
{%- for item in items -%}
{{ item.id }},{{ item.name }}
{% endfor -%}
```
Produces:
```
1,Item1
2,Item2
3,Item3
```
### Email Templates
```
Hello {{ user.name }},
{%- if order %}
Your order details:
- Order ID: {{ order.id }}
- Total: ${{ order.total }}
{%- endif %}
Best regards,
Team
```
### JSON Output
```
{
"items": [
{%- for item in items %}
{
"id": {{ item.id }},
"name": "{{ item.name }}"
}{{ if not forloop.last }},{% endif -%}}
{%- endfor %}
]
}
```
### Nested Loops with Formatting
```
{%- for category in categories %}
Category: {{ category.name }}
{%- for item in category.items %}
- {{ item }}
{%- endfor -%}}
{% endfor -%}
```
## Common Mistakes
### Over-trimming
```
{%- for item in items -%}{{- item -}}{%- endfor -%}
```
This removes ALL whitespace, including necessary spacing.
**Better approach:** Only trim where needed:
```
{% for item in items -%}
{{ item }}
{% endfor -%}
```
### Inconsistent Indentation
Mixing trimmed and non-trimmed tags:
```
{% for item in items %} {# Doesn't trim #}
{{- item -}} {# Trims expressions #}
{% endfor %} {# Doesn't trim #}
```
**Better:** Be consistent:
```
{%- for item in items %}
{{ item }}
{%- endfor -%}
```
### Trimming Necessary Spaces
```
Hello {{ name }}! {# Good #}
Hello {{- name -}}! {# Bad: "Hellothere!" #}
```
## Debugging Whitespace
### Enable Whitespace Visibility
In your testing environment, show whitespace:
```
{:ok, result} = Mau.render(template, context)
IO.inspect(result) # Shows \n and spacing
```
### Use Different Markers
Test with markers to see what's trimmed:
```
[{% if true -%}content{%- endif %}]
[before {{- "x" -}} after]
```
View the output in a way that shows spaces:
```
result |> String.replace(" ", "ยท") |> IO.puts()
```
## Whitespace Best Practices
1. **Trim only where necessary** - Don't over-trim and lose important spacing
2. **Be consistent** - Use the same trimming pattern throughout templates
3. **Test output** - Always verify the rendered output looks correct
4. **Document intent** - Add comments if trimming is non-obvious:
```
{%- # Remove newline before list #}
<ul>
{%- for item in items %}
<li>{{ item }}</li>
{%- endfor %}
</ul>
```
5. **Read-in-template vs Output** - Remember the template source and output can look very different
## Examples
### Clean Markdown
```
# {{ title }}
{{ description }}
{%- for section in sections %}
## {{ section.name }}
{{ section.content }}
{%- endfor %}
```
### HTML Attributes
```
<div class="container{%- if active %} active{%- endif %}">
Content
</div>
```
Or:
```
<div class="container {% if active %}active{% endif %}">
Content
</div>
```
### Multi-line Conditionals
```
Status:
{%- if active %}
<span class="active">Online</span>
{%- else %}
<span class="inactive">Offline</span>
{%- endif %}
```
### Variable Declaration Block
```
{%- assign prefix = "Item" -%}
{%- assign count = items | length -%}
{{ prefix }} Count: {{ count }}
```
## Troubleshooting
### Extra Whitespace in Output
**Problem:** Output has unexpected spaces or newlines
**Solution:** Add `-` modifiers to trim
```
{%- for item in items -%}
```
### Missing Required Spaces
**Problem:** Output runs together
**Solution:** Don't trim where spaces are needed
```
Hello {{- name -}}! {# Wrong: "Helloname!" #}
Hello {{ name }}! {# Right: "Hello name!" #}
```
### Newlines Disappear
**Problem:** Text that should be on separate lines appears on one line
**Solution:** Don't trim newlines between lines
```
{%- # Keep newline by not trimming right side #}
Line 1
{%- if condition %}
Line 2
{%- endif %}
```
## Summary
| Modifier | Purpose | Example |
|----------|---------|---------|
| `{{- }}` | Trim left | `Text {{- value }}` |
| `{{ -}}` | Trim right | `{{ value -}} Text` |
| `{{- -}}` | Trim both | `{{- value -}}` |
| `{%- %}` | Trim left | `{%- if %}` |
| `{% -%}` | Trim right | `{% endif -%}` |
| `{%- -%}` | Trim both | `{%- if -%}` |
## See Also
- [Template Language Reference](../reference/template-language.md) - Full syntax reference
- [Control Flow Guide](control-flow.md) - Tags that work with whitespace
- [Email Template Examples](../examples/email-templates.md) - Real-world template examples