LWC & Aura

Complex Template Expressions in LWC Are GA in Winter '27: Fewer Getters, Cleaner Templates

By Rishabh Panwar · Published 20 September 2026 · 5 min read · Intermediate

Most LWC components accumulate a particular kind of getter: one that exists only to format a value or stitch together a CSS class string, because the template couldn’t do it. Winter ‘27 makes complex template expressions generally available, which lets a broad subset of JavaScript run directly in the HTML template — and a lot of those getters stop earning their place.

This was Beta in Spring ‘26; Winter ‘27 promotes it to GA with no functional changes beyond the status.

What changes in practice

Before, a template could bind a property but not do much with it. To show a formatted string or a computed class, you exposed a getter:

// component.js — the getter that exists only for the template
get fullLabel() {
  return `${this.record.Name} (${this.record.StageName})`;
}

With complex template expressions, that formatting can move into the template, and the getter disappears:

<!-- component.html -->
<span>{record.Name} ({record.StageName})</span>

The template now reflects what’s actually rendered, and the JavaScript file carries less boilerplate.

The iteration case this fixes

The sharper win is inside loops. A getter has no way of knowing which item in an iteration it is being called for, so the historical workaround was to map over the data in JavaScript first and attach every display value to each record before rendering:

// the old workaround: pre-compute display fields per row
get rows() {
  return this.data.map(r => ({
    ...r,
    displayTotal: `$${r.Amount}`,
    rowClass: r.IsWon ? 'won' : 'open',
  }));
}

With expressions in the template, you can bind the raw data and let the small computations happen where they’re used, rather than reshaping every row in advance.

How to turn it on

It is opt-in per component: set the component’s apiVersion to 66.0 or later in its .js-meta.xml file. Nothing changes globally, so existing components keep behaving exactly as they do until you raise their version deliberately.

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>66.0</apiVersion>
    <isExposed>true</isExposed>
</LightningComponentBundle>

What it isn’t

This is a defined subset of JavaScript expressions, not a licence to put arbitrary code in markup. Side effects, multi-statement logic, and real function bodies still belong in the .js file — the same separation-of-concerns instinct that keeps components testable. Used well, it does the opposite of cluttering the template: it removes indirection, so a reader sees the actual displayed value instead of chasing a getter. Salesforce also confirms the virtual DOM’s performance and security characteristics are preserved, since this is a compile-time feature rather than runtime evaluation.

If you’re deciding where logic should live as components grow, the trade-offs pair with the reasoning in LWC getters vs wire and reactivity — the new expressions shift the line, they don’t erase it.

Frequently asked questions

What are complex template expressions in LWC?

They let you write a broad subset of JavaScript expressions directly inside an LWC HTML template, rather than only binding simple properties. You can format strings, build CSS class strings, and evaluate small conditions in the template itself.

Are complex template expressions generally available?

Yes. They were introduced as Beta in Spring '26 and became generally available in Winter '27. Salesforce states there are no functional changes since the last release apart from the GA status.

How do I enable complex template expressions?

Set the component's apiVersion to 66.0 or later in its .js-meta.xml file. It is opt-in per component, not applied globally, so existing components keep their current behaviour until you raise the version.

What problem do they solve?

They remove getters that exist only to format data or assemble a CSS class string, and they remove a common workaround in iterations where you had to pre-map data in JavaScript because a getter can't know which loop item it is called for.

Do complex template expressions hurt performance or security?

No. Salesforce states they preserve the performance and security characteristics of LWC's virtual DOM rendering. The expressions are a compile-time feature, not runtime string evaluation.

Can I put any JavaScript in the template now?

No. It is a defined subset of JavaScript expressions, not arbitrary code. Complex statements, side effects, and full function bodies still belong in the component's JavaScript file.