Wrapif Tag¶
The {% wrapif %}
tag provides a clean way to conditionally wrap content with HTML elements, eliminating the need to repeat opening and closing tags in conditional blocks. This tag solves the common problem where you need to wrap content in an element only under certain conditions - without it, you'd have to duplicate your content in both the "if" and "else" branches. With wrapif, you write your content once and the wrapping happens conditionally.
Standard Syntax¶
{% load includecontents %}
{% wrapif condition %}
<wrapper-element attribute="value">
{% contents %}Default content{% endcontents %}
</wrapper-element>
{% endwrapif %}
Shorthand Syntax¶
For simple cases, use the compact then
syntax:
Simple Examples¶
Basic Conditional Wrapping¶
When user.is_authenticated
is True:
When user.is_authenticated
is False:
Traditional vs Wrapif¶
Complex Wrappers¶
For complex wrappers that need more than a single element, use the standard syntax with full templates:
{% wrapif user.is_premium %}
<div class="premium-content">
<div class="premium-badge">Premium</div>
<div class="content">
{% contents %}{{ article.content }}{% endcontents %}
</div>
<div class="premium-footer">
{% contents footer %}Exclusive content{% endcontents %}
</div>
</div>
{% endwrapif %}
Conditional Variants¶
Wrapelse¶
Provide an alternative wrapper when the condition is false:
When active:
When inactive:
Wrapelif¶
Handle multiple conditions with {% wrapelif %}
:
{% wrapif priority == "high" %}
<strong class="text-red">
{% contents %}{{ task.title }}{% endcontents %}
</strong>
{% wrapelif priority == "medium" %}
<em class="text-yellow">
{{ contents }}
</em>
{% wrapelif priority == "low" %}
<span class="text-gray">
{{ contents }}
</span>
{% wrapelse %}
<span>
{{ contents }}
</span>
{% endwrapif %}
{% wrapif priority == "high" then "strong" class="text-red" %}
{{ task.title }}
{% wrapelif priority == "medium" then "em" class="text-yellow" %}
{% wrapelif priority == "low" then "span" class="text-gray" %}
{% wrapelse "span" %}
{% endwrapif %}
Note: In shorthand syntax, the content is placed after the first condition and is reused for all conditions
Complex Conditions¶
The tag supports all Django template conditional operators:
Advanced Usage¶
Dynamic Attributes¶
Use template variables for dynamic attributes:
{% wrapif show_button then "button" type="button" class=button_class data-action=action %}
{{ button_text }}
{% endwrapif %}
Nested Wrapif¶
Wrapif tags can be nested for complex conditional structures:
{% wrapif show_section %}
<section class="main-content">
{% contents %}
{% wrapif show_header %}
<header class="section-header">
{% contents %}<h1>{{ section.title }}</h1>{% endcontents %}
</header>
{% endwrapif %}
<div class="section-body">
{{ section.content }}
</div>
{% wrapif show_footer %}
<footer class="section-footer">
{% contents %}<p>Updated: {{ section.updated_at|date }}</p>{% endcontents %}
</footer>
{% endwrapif %}
{% endcontents %}
</section>
{% endwrapif %}
{% wrapif show_section then "section" class="main-content" %}
{% wrapif show_header then "header" class="section-header" %}
<h1>{{ section.title }}</h1>
{% endwrapif %}
<div class="section-body">
{{ section.content }}
</div>
{% wrapif show_footer then "footer" class="section-footer" %}
<p>Updated: {{ section.updated_at|date }}</p>
{% endwrapif %}
{% endwrapif %}
Multiple Named Contents¶
When using standard syntax, you can have multiple named content blocks:
{% wrapif show_card %}
<div class="card">
{% if contents.header %}
<div class="card-header">
{{ contents.header }}
</div>
{% endif %}
<div class="card-body">
{% contents %}Main content{% endcontents %}
</div>
{% if contents.footer %}
<div class="card-footer">
{{ contents.footer }}
</div>
{% endif %}
</div>
{% endwrapif %}
Usage:
{% wrapif user.has_premium %}
{% contents header %}Premium Feature{% endcontents %}
This content is only shown to premium users.
{% contents footer %}
<a href="/upgrade">Upgrade your account</a>
{% endcontents %}
{% endwrapif %}
Example Use Cases¶
Conditional Links¶
Dynamic Headings¶
Responsive Containers¶
Permission-Based Wrapping¶
Form Field Validation¶
{% wrapif field.errors %}
<div class="field-group error">
{% contents %}
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
{% if field.errors %}
<div class="error-messages">
{% for error in field.errors %}
<span class="error">{{ error }}</span>
{% endfor %}
</div>
{% endif %}
{% endcontents %}
</div>
{% wrapelse %}
<div class="field-group">
{{ contents }}
</div>
{% endwrapif %}
{% wrapif field.errors then "div" class="field-group error" %}
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{{ field }}
{% if field.errors %}
<div class="error-messages">
{% for error in field.errors %}
<span class="error">{{ error }}</span>
{% endfor %}
</div>
{% endif %}
{% wrapelse "div" class="field-group" %}
{% endwrapif %}
Boolean Attributes¶
The wrapif tag properly handles boolean HTML attributes:
When is_required
is True
, outputs:
When is_required
is False
, the input element is not rendered at all (for standard syntax) or rendered without the wrapper (for shorthand with content).
Performance Considerations¶
- Condition evaluation: Conditions are evaluated once per render
- Content rendering: Content is only rendered when the condition matches
- Template caching: Wrapper templates benefit from Django's template caching
Error Handling¶
Invalid Syntax¶
RaisesTemplateSyntaxError: wrapif tag requires a condition
.
Malformed Elements¶
Outputs HTML as-is, but may not be valid HTML.Best Practices¶
1. Use Descriptive Conditions¶
{% wrapif user.can_edit_article then "div" class="editable" %} <!-- ✅ Good -->
{% wrapif flag then "div" %} <!-- ❌ Unclear -->
2. Keep Wrapper Logic Simple¶
For complex wrappers, consider creating a dedicated component instead:
<!-- ✅ Good: Simple wrapper -->
{% wrapif is_featured then "mark" class="featured" %}
{{ title }}
{% endwrapif %}
<!-- ❌ Consider a component: Too complex for wrapif -->
{% wrapif show_complex_layout %}
<div class="complex">
<div class="header">
<span class="icon"></span>
<h3>{{ title }}</h3>
</div>
<div class="body">
{% contents %}...{% endcontents %}
</div>
</div>
{% endwrapif %}
3. Combine with Other Tags¶
Wrapif works well with other Django IncludeContents features:
{% wrapif show_container then "div" class="container" %}
{% includecontents "components/card.html" title=title %}
{{ content }}
{% endincludecontents %}
{% endwrapif %}
Next Steps¶
- Explore HTML Component Syntax for modern component development
- Learn about Props & Attrs for component attributes
- Check out Component Patterns for advanced techniques