Decorators
⚙️ Decorators
In Lightning Web Components, decorators are a powerful feature that enable developers to modify or enhance the behavior of properties and methods within a component class. They act as metadata annotations that instruct the framework on how to treat specific fields or functions.
A decorator is essentially a design pattern that allows dynamic alteration of behavior in JavaScript objects. These decorators are standardized in ECMAScript and adopted in the LWC framework for enhanced reactivity, data flow, and communication between components and Salesforce data sources.
📌 Types of Decorators in LWC
LWC provides three core decorators:
@api – For public communication between components
@track – For reactivity on private properties
@wire – For seamless integration with Salesforce data and Apex classes
Let's understand each decorator with detailed examples:
1️⃣ @api Decorator – Public Interface for Components
The @api decorator is used to expose properties and methods to the parent (owner) component. When a property or method is marked with @api, it becomes publicly accessible from outside the component.
🔸 Use Cases:
Passing data from parent to child
Calling a method in the child component from the parent
📍 Example: Passing a Public Property
🧩 Parent Component: containerBox.html
<template>
<lightning-card title="Parent Component">
<c-display-box box-label='Passed from Parent'></c-display-box>
</lightning-card>
</template>
🧩 Child Component: displayBox.html
<template>
<lightning-card title="Child Component">
<p>{boxLabel}</p>
</lightning-card>
</template>
🧩 displayBox.js
import { LightningElement, api } from 'lwc';
export default class DisplayBox extends LightningElement {
@api boxLabel = 'Default Label';
}
📝 When the
boxLabelis updated in the parent, the child will automatically re-render with the new value.
📍 Example: Exposing a Public Method
You can call a method in the child component from the parent using @api.
🧩 Parent Template: containerBox.html
<template>
<lightning-card title="Parent Component">
<c-display-box box-label="Initial Value"></c-display-box>
<lightning-button
variant="brand"
label="Call Child Function"
onclick={handleButtonClick}>
</lightning-button>
</lightning-card>
</template>
🧩 containerBox.js
import { LightningElement } from 'lwc';
export default class ContainerBox extends LightningElement {
handleButtonClick() {
this.template.querySelector('c-display-box').updateLabel();
}
}
🧩 Child Component Logic: displayBox.js
import { LightningElement, api } from 'lwc';
export default class DisplayBox extends LightningElement {
@api boxLabel = 'Default';
@api updateLabel() {
this.boxLabel = 'Updated by Parent';
console.log('Child method executed');
}
}
2️⃣ @track Decorator – Reactive Private State
Use the @track decorator when you want changes in object properties to be reflected in the DOM. It's used to track internal state within a component.
⚠️ Note: As of Salesforce Spring '20, all fields used in templates are reactive by default. However,
@trackis still useful for tracking changes in nested objects or arrays.
📍 Example: Reactive Object
🧩 Template: userForm.html
<template>
<lightning-card title="Track Decorator Example">
<p>First Name: {user.firstName}</p>
<p>Last Name: {user.lastName}</p>
<lightning-input
label="First Name"
name="firstName"
onchange={handleInput}>
</lightning-input>
<lightning-input
label="Last Name"
name="lastName"
onchange={handleInput}>
</lightning-input>
</lightning-card>
</template>
🧩 JS Controller: userForm.js
import { LightningElement, track } from 'lwc';
export default class UserForm extends LightningElement {
@track user = {
firstName: 'Default',
lastName: 'User'
};
handleInput(event) {
const { name, value } = event.target;
this.user[name] = value;
}
}
📌 Modifying nested properties inside
@trackensures re-rendering in the DOM.
3️⃣ @wire Decorator – Reactive Salesforce Data Access
The @wire decorator allows automatic binding of Salesforce data (from Apex methods or base Lightning Data Service adapters) to a component.
🔹 Key Features:
Reactive
Auto-updates when Salesforce data changes
Uses
@AuraEnabled(cacheable=true)Apex methods for performance
📍 Example: Using @wire with Apex
🔧 Apex Controller: LWC_ControllerClass.cls
public class LWC_ControllerClass {
@AuraEnabled(cacheable=true)
public static List<Account> accRecords() {
return [SELECT Id, Name FROM Account LIMIT 10];
}
}
🧩 Option 1: Wire Result to JS Function
Template: accountTable.html
<template>
<lightning-card title="Accounts Table">
<template if:true={fetchedAccounts}>
<table>
<tr><th>Id</th><th>Name</th></tr>
<template for:each={fetchedAccounts} for:item="acc">
<tr key={acc.Id}>
<td>{acc.Id}</td>
<td>{acc.Name}</td>
</tr>
</template>
</table>
</template>
</lightning-card>
</template>
JS Controller: accountTable.js
import { LightningElement, wire, track } from 'lwc';
import getAccounts from '@salesforce/apex/LWC_ControllerClass.accRecords';
export default class AccountTable extends LightningElement {
@track fetchedAccounts;
@wire(getAccounts)
wiredAccounts({ data, error }) {
if (data) {
this.fetchedAccounts = data;
} else if (error) {
console.error('Apex Error:', error);
}
}
}
🧩 Option 2: Wire Result to Property
@wire(getAccounts)
fetchedAccounts;
Access data like:
<template for:each={fetchedAccounts.data} for:item="acc">
And handle error with:
<template if:true={fetchedAccounts.error}>
Apex Error
</template>
✅ Summary
| Decorator | Purpose | Scope | Reactive? |
@api | Make method/property accessible publicly | Public to Parent | Yes |
@track | Track object mutations in template | Internal Component | Yes |
@wire | Bind Salesforce data | External (Apex) | Yes |
Decorators are foundational building blocks in LWC that provide elegant solutions for state management, inter-component communication, and Salesforce integration.

