LWC templates are HTML plus a small set of directives that control rendering. The four you’ll see most are lwc:if/elseif/else, for:each, and iterator.
Conditional rendering: lwc:if / lwc:elseif / lwc:else
Introduced in Spring ‘23, lwc:if replaced the older if:true / if:false directives. The new syntax supports an else if chain, which the old one didn’t.
<template>
<template lwc:if={isLoading}>
<lightning-spinner></lightning-spinner>
</template>
<template lwc:elseif={hasError}>
<p class="error">{errorMessage}</p>
</template>
<template lwc:else>
<ul>
<template for:each={contacts} for:item="c">
<li key={c.Id}>{c.Name}</li>
</template>
</ul>
</template>
</template>
Compared with the legacy form:
<!-- old, still works but deprecated in spirit -->
<template if:true={isLoading}>
<lightning-spinner></lightning-spinner>
</template>
<template if:false={isLoading}>
...
</template>
Use lwc:if in any new code. It’s clearer, supports elseif, and renders fractionally faster because the framework evaluates one expression instead of two.
Iteration: for:each
for:each walks an array and renders the body for each item. Two attributes are mandatory:
for:each={items}— the array.for:item="varName"— the loop variable.key={uniqueId}— a unique key on the direct child. Always required.
<template>
<ul>
<template for:each={contacts} for:item="contact" for:index="i">
<li key={contact.Id}>
{i}. {contact.Name} — {contact.Email}
</li>
</template>
</ul>
</template>
The key attribute is what lets the framework reconcile changes efficiently. Never use the index as the key unless the list is genuinely static — when an item is inserted or removed in the middle, index-based keys cause the framework to re-render every node from that point onward.
Iteration with first/last awareness: iterator
When you need to know whether you’re on the first or last item — for separators, styling, or special handling — switch to iterator:
<template>
<ul class="breadcrumb">
<template iterator:it={crumbs}>
<li key={it.value.id}>
<a href={it.value.url}>{it.value.label}</a>
<template lwc:if={it.last}>
<span class="current"></span>
</template>
<template lwc:else>
<span class="separator">›</span>
</template>
</li>
</template>
</ul>
</template>
Each iteration exposes an object:
| Property | Meaning |
|---|---|
it.value | the current array element |
it.index | zero-based position |
it.first | true for the first element |
it.last | true for the last element |
Note the difference in access: with for:each, you write {contact.Name}. With iterator, you write {it.value.Name} — the array element lives under value.
Choosing between for:each and iterator
| You need… | Use |
|---|---|
| Simple list rendering | for:each |
| Access to the index | for:each with for:index |
| First/last awareness (separators, borders, special last row) | iterator |
| Nested loops | Either — nest the templates, give each a for:item |
Other template directives worth knowing
lwc:ref="name"— modern replacement forthis.template.querySelector(...). Access viathis.refs.name.lwc:dom="manual"— opt out of LWC’s DOM management for that element so you canappendChildfrom JS (rare; usually for third-party libs).lwc:spread={obj}— bind every property of an object to a child component’s attributes in one go. Useful for forwarding props.lwc:slot-bind={data}— pass data into scoped slots (light DOM only).
Common interview gotchas
<template for:each>is the loop, not the rendered element. The actual repeated element is its direct child — and that’s wherekeygoes.- A
templatecan only have one direct child when used withfor:each. Wrap multiple siblings in a single element. keymust be a string or number, and unique within the loop. Objects, arrays, or non-unique values will throw at runtime in dev mode.- You can’t put
lwc:ifandfor:eachon the same<template>. Nest them: afor:eachoutside, anlwc:ifinside (or vice versa).
Verified against: LWC Developer Guide — Directives. Last reviewed 2026-05-17 for Spring ‘26 release.