Why LWC templates need their own formatter
An LWC formatter must understand one small but important difference from plain HTML: Lightning Web Components bind data with unquoted curly-brace expressions, as in value={searchKey}. A regular HTML formatter treats {searchKey} as a normal attribute value and wraps it in quotes, which turns the binding into a literal string and breaks the component. Prettier's lwc parser, used here, knows that braces in attribute values are expressions and leaves them unquoted.
Plain HTML formatting of the same snippet produces value="{searchKey}" and even tries to format the handler name as code; the LWC parser avoids both.
Example
<template><lightning-input label="Search" value={searchKey} onchange={handleChange}></lightning-input><template lwc:if={accounts.data}><template for:each={accounts.data} for:item="acc"><p key={acc.Id}>{acc.Name}</p></template></template></template>
<template
><lightning-input
label="Search"
value={searchKey}
onchange={handleChange}
></lightning-input
><template lwc:if={accounts.data}
><template for:each={accounts.data} for:item="acc"
><p key={acc.Id}>{acc.Name}</p></template
></template
></template
>
The output looks unusual because the input had no whitespace between tags. Prettier treats custom elements as inline, so it will not add visible spaces between them; instead it breaks lines inside the tags. Put line breaks between elements in your source and the output becomes the familiar nested layout.
LWC syntax that is preserved
- Unquoted bindings:
title={cardTitle},onclick={handleClick}. - Iteration:
for:eachwithfor:itemandfor:index, anditerator:it. - Conditionals: the legacy
if:true/if:falseand the newerlwc:if,lwc:elseif,lwc:else. keyattributes,lwc:ref,lwc:spreadand slots.- Classic LWC bindings are simple property references such as
{acc.Name}with no operators or function calls, so the formatter never needs to reflow them; computed values belong in getters in the JavaScript class.
Template errors formatting will not fix
The formatter reprints valid markup; it does not run the LWC compiler. These mistakes survive formatting and only show up when you deploy:
- Quoted bindings.
value="{searchKey}"is kept exactly as written. The compiler rejects it as an ambiguous attribute value: remove the quotes for a binding, or the braces for a literal string. - Missing keys in loops. Every element directly inside
for:eachoriteratorneeds akeybound to a unique value, such askey={acc.Id}. - Mixed conditionals.
lwc:ifand the legacyif:truecannot be combined on the same element, andlwc:elseiforlwc:elsemust directly follow an element withlwc:if. - No root template. The file must start with a single
<template>element that wraps everything else.
Using the LWC formatter on a whole component bundle
A Lightning Web Component is a folder with several files: myComponent.html (the template), myComponent.js (the class that extends LightningElement), an optional myComponent.css, and myComponent.js-meta.xml, which declares targets such as lightning__RecordPage. Only the template needs the LWC parser. The meta file is plain XML and can be tidied with the XML Formatter; the stylesheet is ordinary CSS.
Tips
Salesforce DX project templates ship with a Prettier configuration, and teams differ between 2- and 4-space indentation; pick whichever your repository's .prettierrc uses so the output matches your commits. The component's JavaScript controller can be formatted with JavaScript Pretty Print. For Aura or Visualforce markup, which use different expression syntax ({!v.value}), the HTML Formatter is a safer choice. Your markup is processed in the browser only.