<if> : The Conditional Rendering Element
The <if> element is a powerful Scryber component that conditionally renders content based on boolean expressions. It enables dynamic content control, allowing you to show or hide sections of your PDF based on data, user permissions, configuration settings, or any boolean condition.
The
ifelement is similar to the handlebars{{#if condition }}helper. However it does not provide support forelseandelse ifcontent. The library also provides thechoosewithwhenandotherwiseto match the#ifcapabilities, and more.
On this page
- Usage
- Supported Attributes
- Data Binding and Expressions
- Notes
- Examples
- Basic Conditional Content
- User Role-Based Content
- Conditional Table Sections
- Status-Dependent Styling
- Nested Conditions
- Conditional Warnings and Notices
- Date-Based Content
- Conditional Footers
- Complex Business Logic
- Conditional Images
- Report Sections Based on Data
- Conditional Terms and Conditions
- Conditional Price Display
- Permission-Based Document Sections
- Conditional QR Codes or Barcodes
- Multi-Language Conditional Content
- Conditional Page Breaks
- Invoice Payment Status
- See Also
Usage
The <if> element controls content rendering that:
- Shows or hides content based on boolean expressions
- Evaluates conditions during data binding phase
- Supports complex expressions with logical operators
- Can nest other conditional elements
- Integrates seamlessly with data binding
- Removes content completely when false (not just hidden)
- Works with any type of content (text, elements, tables, images)
<!-- Simple condition -->
<if data-test="{{model.showDetails}}">
<div>Detailed information here</div>
</if>
<!-- Conditional sections -->
<if data-test="{{model.userRole == 'Admin'}}">
<div>Admin-only content</div>
</if>
Supported Attributes
Conditional Attributes
| Attribute | Type | Description |
|---|---|---|
data-test |
boolean expression | Required. Boolean expression that determines if content is rendered. When true, content is included; when false, content is completely omitted. |
data-template |
HTML string | Optional. Inline HTML content to render when condition is true. Overrides child elements. |
Standard Attributes
| Attribute | Type | Description |
|---|---|---|
hidden |
string | Additional visibility control. Set to “hidden” to prevent rendering regardless of test condition. |
Data Binding and Expressions
Boolean Expressions
The data-test attribute accepts any expression that evaluates to a boolean:
<!-- Direct boolean property -->
<if data-test="{{model.isActive}}">Active content</if>
<!-- Comparison operators -->
<if data-test="{{model.age >= 18}}">Adult content</if>
<if data-test="{{model.status == 'approved'}}">Approved content</if>
<!-- Logical operators -->
<if data-test="{{model.isAdmin && model.isActive}}">Admin active content</if>
<if data-test="{{model.quantity > 0 || model.allowBackorder}}">Available</if>
<!-- Negation -->
<if data-test="{{!model.isDisabled}}">Enabled content</if>
Comparison Operators
Supported operators in expressions:
==- Equal to!=- Not equal to>- Greater than>=- Greater than or equal to<- Less than<=- Less than or equal to&&- Logical AND||- Logical OR!- Logical NOT
Null and Empty Checks
<!-- Check for null or empty -->
<if data-test="{{model.description != null}}">
<p>{{model.description}}</p>
</if>
<!-- String length check -->
<if data-test="{{model.items.length > 0}}">
<p>Items available</p>
</if>
<if> vs #if vs <choose>
The engine supports both the xml compliant and valid <if> element, along with the handlebars #if notation, along with the <choose> element. Decisions can also be made within styling and visibility based on binding expressions.
And they each offer various advantages and disadvantages…
- Use
{{#if test}} ..content.. {{/if}}when you are already using loops such as{{#each model}} ..content.. {{/each}} - Use
{{#if}}if you do not need to preserve the validity of an xml file. - Use
<choose>when you want to make multiple decisions (when that, or when that, otherwise), and prefer to keep valid xml for processing. - Use
<if>when you want to conditionally include some content based on a single state, and prefer to keep valid xml for processing. - Use
hidden='calc(if(decision, "hidden", ""))'when you want to show or hide an individual static component dynamically.
Notes
Rendering Behavior
The <if> element has important rendering characteristics:
- Complete Removal: When false, content is not rendered at all (not just hidden with CSS)
- Data Binding Phase: Evaluation occurs during data binding, before layout
- No Output: The
<if>element itself produces no output in the PDF - Child Content: Only child content is rendered when condition is true
- Performance: False conditions skip all child processing, improving performance
Nesting and Logic
You can nest <if> elements for complex logic:
<if data-test="{{model.hasPermission}}">
<if data-test="{{model.isActive}}">
<!-- Content shown only if both conditions true -->
</if>
</if>
Alternative Approaches
For simple show/hide, you can also use:
hiddenattribute with expression:<div hidden="{{!model.show ? 'hidden' : ''}}">- CSS display:
style="display: {{model.show ? 'block' : 'none'}}"
However, <if> is more efficient as it doesn’t process content at all when false.
Inline Template
The data-template attribute allows inline content definition, useful for simple conditional text:
<if data-test="{{model.status == 'urgent'}}"
data-template="<span style='color: red; font-weight: bold;'>URGENT</span>">
</if>
Examples
Basic Conditional Content
<!-- Show discount section only if discount exists -->
<if data-test="{{model.discount > 0}}">
<div style="color: red; font-weight: bold;">
Save {{model.discount}}%!
</div>
</if>
User Role-Based Content
<!-- Admin-only section -->
<if data-test="{{model.userRole == 'Admin'}}">
<div style="background-color: #fff3cd; padding: 10pt; margin: 10pt 0;">
<strong>Admin View:</strong> Internal reference #{{model.internalId}}
</div>
</if>
<!-- Public content always shows -->
<div>
<h2>{{model.title}}</h2>
<p>{{model.description}}</p>
</div>
Conditional Table Sections
<table style="width: 100%;">
<thead>
<tr>
<th>Product</th>
<th>Price</th>
<if data-test="{{model.showCost}}">
<th>Cost</th>
<th>Margin</th>
</if>
</tr>
</thead>
<tbody>
<template data-bind="{{model.products}}">
<tr>
<td>{{.name}}</td>
<td>${{.price}}</td>
<if data-test="{{model.showCost}}">
<td>${{.cost}}</td>
<td>{{.margin}}%</td>
</if>
</tr>
</template>
</tbody>
</table>
Status-Dependent Styling
<div class="order">
<h3>Order #{{model.orderNumber}}</h3>
<if data-test="{{model.status == 'completed'}}">
<div style="color: green; font-weight: bold;">
Status: Completed âś“
</div>
</if>
<if data-test="{{model.status == 'pending'}}">
<div style="color: orange; font-weight: bold;">
Status: Pending...
</div>
</if>
<if data-test="{{model.status == 'cancelled'}}">
<div style="color: red; font-weight: bold;">
Status: Cancelled âś—
</div>
</if>
</div>
Nested Conditions
<if data-test="{{model.hasOrders}}">
<div class="orders-section">
<h2>Your Orders</h2>
<if data-test="{{model.orders.length > 0}}">
<template data-bind="{{model.orders}}">
<div class="order-item">
<span>Order {{.id}}</span>
<if data-test="{{.isRush}}">
<span style="color: red; font-weight: bold;">RUSH</span>
</if>
</div>
</template>
</if>
<if data-test="{{model.orders.length == 0}}">
<p style="color: #666; font-style: italic;">No orders found.</p>
</if>
</div>
</if>
Conditional Warnings and Notices
<!-- Low stock warning -->
<if data-test="{{model.stockLevel < 10}}">
<div style="background-color: #fff3cd; border: 1pt solid #ffc107;
padding: 10pt; margin: 10pt 0;">
<strong>Warning:</strong> Low stock - only {{model.stockLevel}} items remaining
</div>
</if>
<!-- Out of stock error -->
<if data-test="{{model.stockLevel == 0}}">
<div style="background-color: #f8d7da; border: 1pt solid #dc3545;
padding: 10pt; margin: 10pt 0;">
<strong>Error:</strong> Out of stock
</div>
</if>
Date-Based Content
<!-- Show expiration warning if date is soon -->
<if data-test="{{model.daysUntilExpiration < 30}}">
<div style="color: red;">
Expires in {{model.daysUntilExpiration}} days!
</div>
</if>
<!-- Show renewal message if expired -->
<if data-test="{{model.isExpired}}">
<div style="background-color: #f8d7da; padding: 10pt;">
This subscription has expired. Please renew.
</div>
</if>
Conditional Footers
<div class="page-footer">
<div style="text-align: center;">
Page <page></page> of <page property="total"></page>
</div>
<if data-test="{{model.isConfidential}}">
<div style="text-align: center; color: red; font-weight: bold; margin-top: 5pt;">
CONFIDENTIAL - DO NOT DISTRIBUTE
</div>
</if>
<if data-test="{{model.isDraft}}">
<div style="text-align: center; color: #666; font-style: italic; margin-top: 5pt;">
DRAFT - Not for Distribution
</div>
</if>
</div>
Complex Business Logic
<if data-test="{{model.customer.isPremium && model.order.total > 100}}">
<div style="background-color: #d4edda; border: 1pt solid #28a745; padding: 10pt;">
<strong>Premium Discount Applied!</strong> You saved ${{model.premiumDiscount}}
</div>
</if>
<if data-test="{{!model.customer.isPremium && model.order.total > 500}}">
<div style="background-color: #cce5ff; border: 1pt solid #0066cc; padding: 10pt;">
<strong>Upgrade to Premium</strong> and save {{model.potentialSavings}} on this order!
</div>
</if>
Conditional Images
<if data-test="{{model.product.hasImage}}">
<img src="{{model.product.imageUrl}}"
style="width: 200pt; height: 200pt; object-fit: cover;"/>
</if>
<if data-test="{{!model.product.hasImage}}">
<div style="width: 200pt; height: 200pt; background-color: #eee;
display: flex; align-items: center; justify-content: center;">
<span style="color: #999;">No image available</span>
</div>
</if>
Report Sections Based on Data
<h1>{{model.reportTitle}}</h1>
<if data-test="{{model.includeSummary}}">
<section>
<h2>Executive Summary</h2>
<p>{{model.summary}}</p>
</section>
</if>
<if data-test="{{model.includeDetails}}">
<section>
<h2>Detailed Analysis</h2>
<template data-bind="{{model.details}}">
<div>{{.content}}</div>
</template>
</section>
</if>
<if data-test="{{model.includeCharts}}">
<section>
<h2>Charts and Graphs</h2>
<!-- Chart content -->
</section>
</if>
Conditional Terms and Conditions
<h2>Terms and Conditions</h2>
<div>{{model.standardTerms}}</div>
<if data-test="{{model.contractType == 'enterprise'}}">
<div style="margin-top: 15pt;">
<h3>Enterprise Terms</h3>
<p>{{model.enterpriseTerms}}</p>
</div>
</if>
<if data-test="{{model.hasCustomTerms}}">
<div style="margin-top: 15pt;">
<h3>Custom Terms</h3>
<p>{{model.customTerms}}</p>
</div>
</if>
Conditional Price Display
<div class="product-price">
<if data-test="{{model.onSale}}">
<div>
<span style="text-decoration: line-through; color: #999;">
${{model.regularPrice}}
</span>
<span style="color: red; font-weight: bold; font-size: 14pt; margin-left: 10pt;">
${{model.salePrice}}
</span>
</div>
</if>
<if data-test="{{!model.onSale}}">
<div style="font-size: 14pt; font-weight: bold;">
${{model.regularPrice}}
</div>
</if>
</div>
Permission-Based Document Sections
<div class="document">
<!-- Public section - always visible -->
<section>
<h2>Overview</h2>
<p>{{model.publicOverview}}</p>
</section>
<!-- Member-only section -->
<if data-test="{{model.userLevel >= 1}}">
<section style="page-break-before: always;">
<h2>Member Information</h2>
<p>{{model.memberContent}}</p>
</section>
</if>
<!-- Premium member section -->
<if data-test="{{model.userLevel >= 2}}">
<section style="page-break-before: always;">
<h2>Premium Analysis</h2>
<p>{{model.premiumContent}}</p>
</section>
</if>
<!-- Admin section -->
<if data-test="{{model.userLevel >= 99}}">
<section style="page-break-before: always; background-color: #f0f0f0;">
<h2>Administrative Data</h2>
<p>{{model.adminContent}}</p>
</section>
</if>
</div>
Conditional QR Codes or Barcodes
<if data-test="{{model.includeQRCode}}">
<div style="text-align: center; margin: 20pt 0;">
<img src="{{model.qrCodeUrl}}" style="width: 100pt; height: 100pt;"/>
<div style="font-size: 8pt; color: #666; margin-top: 5pt;">
Scan for more information
</div>
</div>
</if>
Multi-Language Conditional Content
<if data-test="{{model.language == 'en'}}">
<div>
<h1>Welcome</h1>
<p>Thank you for your order.</p>
</div>
</if>
<if data-test="{{model.language == 'es'}}">
<div>
<h1>Bienvenido</h1>
<p>Gracias por su pedido.</p>
</div>
</if>
<if data-test="{{model.language == 'fr'}}">
<div>
<h1>Bienvenue</h1>
<p>Merci pour votre commande.</p>
</div>
</if>
Conditional Page Breaks
<template data-bind="{{model.sections}}">
<div class="section">
<h2>{{.title}}</h2>
<p>{{.content}}</p>
<!-- Only break page if this isn't the last section -->
<if data-test="{{!$islast}}">
<div style="page-break-after: always;"></div>
</if>
</div>
</template>
Invoice Payment Status
<div class="invoice">
<h1>Invoice #{{model.invoiceNumber}}</h1>
<!-- Invoice details -->
<div>Total: ${{model.total}}</div>
<if data-test="{{model.isPaid}}">
<div style="color: green; font-size: 16pt; font-weight: bold; margin-top: 20pt;">
PAID - {{model.paymentDate}}
</div>
</if>
<if data-test="{{!model.isPaid && !model.isOverdue}}">
<div style="color: orange; font-size: 16pt; font-weight: bold; margin-top: 20pt;">
PAYMENT DUE - {{model.dueDate}}
</div>
</if>
<if data-test="{{!model.isPaid && model.isOverdue}}">
<div style="color: red; font-size: 16pt; font-weight: bold; margin-top: 20pt;">
OVERDUE - Payment Required Immediately
</div>
<div style="background-color: #f8d7da; padding: 10pt; margin-top: 10pt;">
This invoice is {{model.daysOverdue}} days overdue.
Late fees may apply.
</div>
</if>
</div>
See Also
- template - Template element for repeating content
- Data Binding - Complete guide to data binding expressions
- Expressions - Expression syntax and functions
- hidden attribute - Alternative visibility control
- Choose Component - Multi-condition selection (if/else if/else)
- div - Generic container element