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.