we are committed to delivering innovative solutions that drive growth and add value to our clients. With a team of experienced professionals and a passion for excellence.

Follow us

Complex Template Expressions in LWC – Ternary Operators and Logic Directly in Templates

Complex Template Expressions in LWC – Ternary Operators and Logic Directly in Templates

Images
Authored by
Nitish Jadhav
Date Released
June 30, 2026
Comments
No Comments

INTRODUCTION

LWC templates have always been limited: simple property bindings work great, but anything more complex required getters in JavaScript. Need to show different text based on a condition? Create a getter. Need to format data? Create a getter. Multiple getters meant extra code, more boilerplate, and harder-to-read components.

Spring ’26 introduces Complex Template Expressions (Beta)—the ability to write ternary operators, conditional logic, and simple operations directly in templates. No more getter boilerplate for common patterns. HTML stays close to its logic. Components become more readable.

This post explores what complex template expressions enable, common patterns, and best practices for using them effectively.


THE GETTER BOILERPLATE PROBLEM

Why This Feature Was Needed

The Before Scenario: Getters for Everything

Problem 1: Simple Conditional

javascript

// JavaScript – Before

export default class EmployeeCard extends LightningElement {

    @track empFirstName = ‘John’;

    @track empLastName = ‘Doe’;

    @track empSalary = 50000;

    @track isActive = true;

    // Getter just for conditional logic

    get empStatus() {

        return this.isActive ? ‘Active’ : ‘Inactive’;

    }

}

html

<!– Template – Before –>

<template>

    <lightning-card title=”Employee“>

        <p>{empFirstName} {empLastName}</p>

        <p>Status: {empStatus}</p>  <!– Uses getter –>

    </lightning-card>

</template>

Problem 2: Complex Conditional

javascript

// JavaScript – Before

export default class EmployeeCard extends LightningElement {

    @track empAge = 18;

    @track empSalary = 50000;

    // Getter for age category

    get ageCategory() {

        return this.empAge >= 18 ? ‘Adult’ : ‘Minor’;

    }

    // Getter for tax bracket

    get taxBracket() {

        return this.empSalary > 50000 ? ‘Tax’ : ‘No Tax’;

    }

    // Getter combining conditions

    get fullStatus() {

        return this.ageCategory + ‘ / ‘ + this.taxBracket;

    }

}

html

<!– Template – Before –>

<p>{fullStatus}</p>

Problem 3: Multiple Getters for Simple Logic

javascript

// JavaScript – Before: Many getters!

export default class EmployeeCard extends LightningElement {

    @track empAge = 18;

    @track empSalary = 50000;

    @track isActive = true;

    get ageGroup() {

        return this.empAge >= 18 ? ‘Adult’ : ‘Minor’;

    }

    get taxStatus() {

        return this.empSalary > 50000 ? ‘Tax’ : ‘No Tax’;

    }

    get activeClass() {

        return this.isActive ? ‘active’ : ‘inactive’;

    }

    get displayName() {

        return this.isActive ? this.firstName + ‘ ‘ + this.lastName : ‘Unknown’;

    }

    // 4 getters for relatively simple logic

}


COMPLEX TEMPLATE EXPRESSIONS

What Spring ’26 Enables

What Complex Expressions Include

Feature 1: Ternary Operators

html

<!– Simple ternary –>

<p>{isActive ? ‘Active’ : ‘Inactive’}</p>

<!– Nested ternary –>

<p>{

    age >= 18 ? ‘Adult’ : ‘Minor’

}</p>

<!– Complex nested –>

<p>{

    status === ‘active’ ? ‘Active Now’ : 

    status === ‘pending’ ? ‘Pending’ : 

    ‘Inactive’

}</p>

Feature 2: Arithmetic Operations

html

<!– Addition –>

<p>Total: {price + tax}</p>

<!– Subtraction –>

<p>Discount: {originalPrice – salePrice}</p>

<!– Multiplication –>

<p>Total Items: {quantity * unitPrice}</p>

<!– Division –>

<p>Average: {totalAmount / itemCount}</p>

Feature 3: Comparison Operators

html

<!– Greater than –>

<p>{salary > 50000 ? ‘High’ : ‘Standard’}</p>

<!– Less than –>

<p>{age < 18 ? ‘Minor’ : ‘Adult’}</p>

<!– Equality –>

<p>{status === ‘active’ ? ‘Active’ : ‘Inactive’}</p>

<!– Not equal –>

<p>{role !== ‘admin’ ? ‘User’ : ‘Administrator’}</p>

Feature 4: Logical Operators

html

<!– AND –>

<p>{isActive && hasPermission ? ‘Allowed’ : ‘Denied’}</p>

<!– OR –>

<p>{isAdmin || isSupervisor ? ‘Can Approve’ : ‘Cannot Approve’}</p>

<!– NOT –>

<p>{!isActive ? ‘Inactive’ : ‘Active’}</p>

Feature 5: String Operations

html

<!– Concatenation –>

<p>{firstName + ‘ ‘ + lastName}</p>

<!– Method calls –>

<p>{email.toLowerCase()}</p>

<p>{name.toUpperCase()}</p>

<p>{phone.substring(0, 3)}</p>

Feature 6: Method Calls (Limited)

html

<!– Method invocation –>

<p>{formatDate(dateField)}</p>

<!– Array methods –>

<p>{items.length > 0 ? ‘Has items’ : ‘Empty’}</p>


COMMON PATTERNS

Practical Use Cases

Pattern 1: Conditional Text

Before:

javascript

get statusText() {

    return this.isActive ? ‘Currently Active’ : ‘Inactive’;

}

html

<p>{statusText}</p>

After:

html

<p>{isActive ? ‘Currently Active’ : ‘Inactive’}</p>

Use Case:
Simple conditional display. Best for short text alternatives.

Pattern 2: Conditional CSS Classes

Before:

javascript

get successClass() {

    return this.isSuccessful ? ‘slds-text-color_success’ : ‘slds-text-color_error’;

}

html

<div class=”{successClass}“>

    {message}

</div>

After:

html

<div class=”{isSuccessful ? slds-text-color_success : slds-text-color_error}“>

    {message}

</div>

Use Case:
Conditional styling. Classes directly tied to condition.

Pattern 3: Formatted Display

Before:

javascript

get formattedDate() {

    return new Date(this.createdDate).toLocaleDateString();

}

html

<p>Created: {formattedDate}</p>

After:

html

<p>Created: {new Date(createdDate).toLocaleDateString()}</p>

Use Case:
Formatting data for display. Keep formatting in template.

Pattern 4: Numeric Calculations

Before:

javascript

get totalPrice() {

    return this.quantity * this.unitPrice;

}

get totalWithTax() {

    return this.totalPrice + (this.totalPrice * 0.1);

}

html

<p>Total: {totalWithTax}</p>

After:

html

<p>Total: {quantity * unitPrice + (quantity * unitPrice * 0.1)}</p>

Use Case:
Simple calculations in display context.

Pattern 5: Conditional Rendering

Before:

javascript

get showPremiumBadge() {

    return this.userType === ‘premium’ && this.isActive;

}

html

<template if:true={showPremiumBadge}>

    <span>Premium</span>

</template>

After:

html

<template if:true={userType === ‘premium’ && isActive}>

    <span>Premium</span>

</template>

Use Case:
Conditional block display. Show/hide based on expression.

Pattern 6: Dynamic Attributes

Before:

javascript

get placeholderText() {

    return this.type === ’email’ ? ‘Enter email’ : ‘Enter text’;

}

html

<lightning-input placeholder={placeholderText}></lightning-input>

After:

html

<lightning-input 

    placeholder={type === ’email’ ? ‘Enter email’ : ‘Enter text’}>

</lightning-input>

Use Case:
Dynamic attribute values. Set based on conditions.


LIMITATIONS AND BOUNDARIES

What Complex Expressions Can’t Do

Limitations

Limitation 1: No Function Definitions

html

<!–  Cannot define functions –>

<p>{function() { return ‘test’; }}</p>

<!–  Can call existing methods –>

<p>{myMethod()}</p>

Limitation 2: No Assignment

html

<!–  Cannot assign values –>

<p>{x = 5}</p>

<!–  Can use existing properties –>

<p>{x}</p>

Limitation 3: No Complex Statements

html

<!–  Cannot use if/else/for/while –>

<p>{if (x > 5) { return ‘yes’; }}</p>

<!–  Can use ternary –>

<p>{x > 5 ? ‘yes’ : ‘no’}</p>

Limitation 4: Limited Array Operations

html

<!–  Cannot use forEach or other complex array methods –>

<p>{items.forEach(item => item.name)}</p>

<!–  Can access length and basic properties –>

<p>{items.length > 0 ? ‘Has items’ : ‘Empty’}</p>

When to Still Use Getters

Use Getters For:

  • Complex logic that’s hard to read in template
  • Operations that happen frequently (performance)
  • Reusable calculations used in multiple places
  • Business logic that should be in component

PERFORMANCE CONSIDERATIONS

When Complex Expressions Matter for Performance

Performance Benefit: Reduced Getter Calls

Before (Without Complex Expressions):

html

<!– Each expression evaluates a getter –>

<p>{statusText}</p>  <!– Calls getter –>

<p>{ageGroup}</p>    <!– Calls getter –>

<p>{taxStatus}</p>   <!– Calls getter –>

After (With Complex Expressions):

html

<!– Expressions evaluated inline, no extra function calls –>

<p>{isActive ? ‘Active’ : ‘Inactive’}</p>

<p>{age >= 18 ? ‘Adult’ : ‘Minor’}</p>

<p>{salary > 50000 ? ‘Tax’ : ‘No Tax’}</p>

Impact:
Marginal performance improvement by eliminating function call overhead. Usually negligible unless used in loops.

Performance Caveat: In Loops

html

<!–  Expression evaluated for EVERY item –>

<template for:each={employees} for:item=”emp“>

    <p key={emp.id}>

        {emp.salary > 50000 ? ‘High’ : ‘Standard’}

    </p>

</template>

Better approach:

html

<!– Let each component handle its own formatting –>

<template for:each={employees} for:item=”emp“>

    <c-employee-card employee={emp}></c-employee-card>

</template>

javascript

// Child component

export default class EmployeeCard extends LightningElement {

    @api employee;

    get salaryCategory() {

        return this.employee.salary > 50000 ? ‘High’ : ‘Standard’;

    }

}


BEST PRACTICES

Using Complex Expressions Effectively

Best Practice 1: Use for Display Logic Only

Do:

html

<!– Format for display –>

<p>{amount > 1000 ? ‘$’ + amount : amount}</p>

<!– Conditional text –>

<p>{status === ‘active’ ? ‘Active’ : ‘Inactive’}</p>

Don’t:

html

<!– Complex business logic –>

<p>{calculateTaxes() && validatePermissions() ? ‘Allowed’ : ‘Denied’}</p>

<!– Side effects –>

<p>{saveData() ? ‘Saved’ : ‘Failed’}</p>

Best Practice 2: Keep Expressions Short and Simple

Do:

html

<p>{isActive ? ‘Active’ : ‘Inactive’}</p>

Don’t:

html

<p>{

    this.user.status === ‘active’ && 

    this.user.permissions.includes(‘write’) && 

    !this.user.isOnLeave && 

    this.organization.isActive ? 

    ‘User Can Perform Action’ : 

    ‘User Cannot Perform Action’

}</p>

Best Practice 3: Use Getters for Complex Logic

Pattern:

  • Simple expressions: use template expressions
  • Complex logic: use getters
  • Very complex: use methods

Best Practice 4: Comment Non-Obvious Expressions

html

<!– 

    Determine user tier based on total purchases

    Threshold: $1000 for premium, $500 for standard

–>

<p>{totalPurchases > 1000 ? ‘Premium’ : totalPurchases > 500 ? ‘Standard’ : ‘Basic’}</p>

Best Practice 5: Combine with Template if:true

html

<!– Cleaner conditional rendering –>

<template if:true={userType === ‘admin’ && isActive}>

    <span>Administrator</span>

</template>

<!– Instead of –>

<template if:true={showAdminBadge}>

    <span>Administrator</span>

</template>


FINAL THOUGHTS

Complex Template Expressions represent a maturation of LWC’s templating capabilities. For years, LWC required getters for anything beyond simple property binding. That limitation meant extra code, split logic, and more boilerplate.

This feature doesn’t eliminate the need for getters—complex business logic still belongs in JavaScript. But for the 80% of cases that are simple conditionals, formatting, or calculations, expressions in templates are cleaner and more readable.

The key is restraint: use expressions for display logic, keep business logic in getters. The sweet spot is expressions that are short enough to understand at a glance, but complex enough to eliminate simple getters.

 

Leave a Reply

Your email address will not be published. Required fields are marked *