Saturday 18 February 2023

Conditional LWC Directives in Spring '23

 Introduction

The Spring '23 release of Salesforce is now fully live, after a last minute delay in the US. One of the new features was a set of Lightning Web Component directives for conditional rendering. A relatively minor change, but in my view one with a large impact, as it adds clarity. And as we all know, clarity is the gift that keeps on giving to everyone that works on the component after you.

Old Mechanism

The previous conditional directives were if:true and if:false. Nothing wrong with these per se, but once you start nesting things the clarity starts to leak away. Consider a made up example of a search results page where I want to :

  • display a placeholder if a search hasn't been run
  • display a message if the search has been run but there are no results
  • display the results if the search has been run and there are results
  • display the result count on the right hand side if the search is run and there are results
  • display an additional message if there are more than the 100 results displayed on the page

To assist me I have a few properties - searchRun, hasResults, hasMoreResults, resultCount, and my markup is:
<template if:true={searchRun}>
    <template if:true={hasResults}>
        Results go here!
        <template if:true={hasMoreResults}>
            More than 10 results - please refine your search
        </template>
    </template>
    <div style="float:right">{resultCount} results</div>
    <template if:false={hasResults}>
        Search returned no results
    </template>
 </template>
 <template if:false={searchRun}>
     No search run.
 </template>

While it's not terrible, it's also a bit confusing - lots of true/false and I have to examine the property binding to figure out the relationship between them. The eagle-eyed will also spot the bug - my result count sits outside of the conditional for hasResults, so will be displayed in all cases. This is easily done when the if and else conditionals are independent of each other.

New Mechanism

The new conditionals are lwc:if, lwc:elif and lwc:else. Note that these are dependent on each other - you can't have an lwc:else unless it follows an lwc:if, and it is executed if the lwc:if evaluates to false.

Reworking the markup from above gives me:

<template lwc:if={searchRun}>
    <template lwc:if={hasResults}>
        Results go here!
        <template lwc:if={hasMoreResults}>
            More than 10 results - please refine your search
        </template>
        <div style="float:right">{resultCount} results</div>
    </template>
    <template lwc:else>
        Search returned no results
    </template>
</template>
<template lwc:else>
    No search run.
</template>

which I think is much clearer. I can easily see the markup that will render when the properties evaluate to true or not, and I can see the dependencies as the lwc:else (or lwc:elif) always follows an lwc:if (or lwc:elif). Even more so when I collapse the if template body in VS Code:

Another benefit is that I can't misplace my result count div - if I try to place markup between two dependent lwc conditional directives, in this case between lwc:if and lwc:else, it is immediately called out as a problem:


Related Posts

I've waxed lyrical about clarity in the past, regarding the System.Assert class introduced in Winter '23.