Skip to main content

Command Palette

Search for a command to run...

Decorators

Published
4 min readView as Markdown

⚙️ 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:

  1. @api – For public communication between components

  2. @track – For reactivity on private properties

  3. @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 boxLabel is 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, @track is 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 @track ensures 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

DecoratorPurposeScopeReactive?
@apiMake method/property accessible publiclyPublic to ParentYes
@trackTrack object mutations in templateInternal ComponentYes
@wireBind Salesforce dataExternal (Apex)Yes

Decorators are foundational building blocks in LWC that provide elegant solutions for state management, inter-component communication, and Salesforce integration.

More from this blog

B

BlackBUC

29 posts