Lightning Web Components Cheat Sheet 2nd Edition
Lightning Web Components Cheat Sheet 2nd Edition
OVERVIEW
Lightning Web Components (LWC) is a framework for creating modern UI on web, mobile apps and digital experience on
Salesforce platform. Aura Components and LWC both coexist and interoperate on the page. It leverages web standards and delivers
high performance. It is treated as Lighting Components.
• In VS Code, press Command + Shift P, enter sfdx , and select SFDX: Create Project.
Create • Enter MyLWC as project name
Salesforce DX
Project
• In VS Code, press Command + Shift P, enter sfdx , and select SFDX: Authorize an Org.
• Press Enter to accept Project Login URL option,
Authorize an
Org • Accept default alias
• In VS Code, press Command + Shift P, enter sfdx, select SFDX: Create Lightning Web Component.
• Enter myHelloWorld as name of the component.
Create a LWC • Enter to accept the default force-app/main/default/lwc folder.
• In VS Code, press Command + Shift P, enter sfdx, select SFDX: Open Default Org
Add • Open the page (Edit Page) where component to be added and drag myHelloWorld component and save.
Component to
App
To create a component, first create folder and it consists of following components where first three are mandatory.
1
End UI Controller Configuration
Style (.css)
(HTML) (.js) (.js-meta.xml)
Resource
Additional .js __tests__
(.svg)
HTML FILE
<!-- myComponent.html --> UI components should have HTML file, service components don’t
<template> need.
<!-- Replace comment with component HTML --> When component renders <template> tag will be replaced by name
</template> of component <namespace-component-name>, like myComponent
renders as <c-my-component> where c is default namespace.
CONTROLLER
CONFIGURATION
<?xml version="1.0" encoding="UTF-8"?> Configuration file defines metadata values, including design
<LightningComponentBundle configuration for Lightning App Builder and Community
xmlns="http://soap.sforce.com/2006/04/metadata"> Builder. Include the configuration file in your component’s
project folder, and push it to your org along with the
<apiVersion>54.0</apiVersion>
other component files.
<isExposed>false</isExposed>
</LightningComponentBundle>
CSS SVG
Reactive Properties: if value changes, component renders. It can be either private or public. When component renders all
expressions in the template as re-evaluated.
Primitive fields—like booleans, numbers, and strings—are reactive. LWC tracks field value changes in a shallow fashion. Changes are
detected when a new value is assigned to the field by comparing the value identity using ===.
@api For exposing public property, this is reactive. If value of a public property used in template changes, the
component rerenders, hence expressions are re-evaluated, renderedCallback() executes
@track To observe changes to the properties of an object or to the elements of an array, use @track. Though
framework doesn't observe mutations made to complex objects, such as objects inheriting from Object,
class instances, Date, Set, or Map.
@wire To get and bind data.
setAttribute() For reflecting JavaScript properties to HTML attributes
Example : Below example shows how @api and @track haven been used.
Data Flow
3
Parent Child
<!-- todoapp.html --> <!-- c-todoitem.html -->
<template> <template>
<c-todowrapper> <p>item in todoitem: {itemName}</p>
<c-todoitem item-name={itemName}></c-todoitem> <p><button onclick={updateItemName}>Update item name in
todoitem</button></p>
</c-todowrapper>
</template>
<p>item in todoapp: {itemName}</p>
<p><button onclick={updateItemName}>Update item name in
todoapp</button></p>
</template>
Value binding
// c-todoapp.js // c-todoitem.js
import { LightningElement, track } from 'lwc'; import { LightningElement, api } from 'lwc';
export default class Todoapp extends LightningElement { export default class Todoitem extends LightningElement {
@track itemName = "Milk"; @api itemName;
updateItemName() { // This code won’t update itemName because:
this.itemName = "updated item name in todoapp"; // 1) You can update public properties only at component construction time.
} updateItemName() {
this.itemName = "updated item name in todoitem";
}
}
Call methods on Children
Owner and parent component can call JavaScript methods on Child components.
Parent Child
<!-- methodCaller.html --> <!-- videoPlayer.html -->
<template> <template>
<div> <div class="fancy-border">
<c-video-player video-url={video}></c-video-player> <video autoplay>
<button onclick={handlePlay}>Play</button> <source src={videoUrl} type={videoType} />
</div> </video>
</template> </div>
</template>
// methodCaller.js // videoPlayer.js
import { LightningElement } from 'lwc'; import { LightningElement, api } from 'lwc';
export default class MethodCaller extends LightningElement { export default class VideoPlayer extends LightningElement {
handlePlay() { play() {
} if (player) {
player.play();
/* }
}
4
The handlePlay() function in c-method-caller calls the play() method get videoType() {
in the c-video-player element. this.template.querySelector('c-video- return 'video/' + this.videoUrl.split('.').pop();
player') returns the c-video-player element in methodCaller.html.
}
*/
}
Spread Properties on Children
Pass set of properties using lwc:spread directive. It accepts one object. lwc:spread can used with event handler.
Parent Child
<!-- methodCaller.html --> <!-- child.html -->
<template> <template>
<c-child lwc:spread={childProps}></c-child> <p>Name: {name}</p>
</template> <p>Country : {country}</p>
</template>
// methodCaller.js // child.js
import { LightningElement } from 'lwc'; import { LightningElement, api } from 'lwc';
export default class MethodCaller extends LightningElement { export default class Child extends LightningElement {
childProps = { name: "James Smith", country: "USA" }; @api name;
} @api country;
}
Access elements the this.template.querySelector() - method is a standard DOM API that returns the first
Component owns element that matches the selector.
this.template.querySelectorAll() - method returns an array of DOM Elements.
Refs – locate DOM without a selector.
//assign it //use it
export default class extends LightningElement {
<template> renderedCallback() {
<div lwc:ref="myDiv"></div> console.log(this.refs.myDiv);
}}
</template>
Access Static Resource import myResource from '@salesforce/resourceUrl/resourceReference';
Access Content Asset import myContentAsset from "@salesforce/contentAssetUrl/contentAssetReference";
Access import intPropertyName from @salesforce/i18n/internationalizationProperty
Internationalization Properties
Access Labels import labelName from '@salesforce/label/labelReference';
Access Current UserId import Id from '@salesforce/user/Id';
Check Permissions import hasPermission from "@salesforce/userPermission/PermissionName";
import hasPermission from "@salesforce/customPermission/PermissionName";
Access Client Form Factor import formFactorPropertyName from "@salesforce/client/formFactor";
DYNAMIC COMPONENTS (DC)
• Config should include lightning__dynamicComponent
• HTML file will have <lwc:component lwc:is={componentConstructor}></lwc:component>
• Selecting dynamic component, use lwc:ref="myCmp" on above statement.
• It can include child elements, <lwc:component> first renders DC, then its children.
• Pass properties using @api
• Pass recordId like this: <lwc:component record-id={recordId} lwc:is={componentConstructor} >
5
WORKING WITH DOM
Shadow DOM Light DOM Synthetic Shadow DOM
Every element of each LWC are encapsulated in When you use light DOM, your It’s a polyfill that mimics native
shadow tree. This part of DOM is hidden from the component lives outside the shadow shadow DOM behavior,
document it contains and hence called shadow tree. DOM and avoids shadow DOM Currently, Lightning Experience
Shadow DOM is a web standard that encapsulates limitations. This approach eases third- and Experience Builder sites use
the elements of a component to keep styling and party integrations and global styling. synthetic shadow by default.
behavior consistent in any context.
<c-todo-app>
#shadow-root
<div>
<p>Your To Do List</p>
</div>
<c-todo-item>
Shadow Boundary #shadow-root
<div>
<p>Go to the store</p>
</div>
</c-todo-item>
</c-todo-app>
Shadow DOM vs. Light DOM
6
COMMUNICATE WITH EVENTS
Create an Event CustomEvent() constructor in the js file
Dispatch an Event EventTarget.dispatch(new CustomEvent(‘event name’)); //in the js file
Pass data with an Event const selectedEvent = new CustomEvent('selected', { detail: this.contact.Id }); //in the js file
this.dispatchEvent(selectedEvent);
Attach Event listener <template><c-child onnotification={handleNotification}></c-child></template>
declaratively
Attach Event listener For components within shadow boundary, use following snippet in js file:
programmatically constructor() {
super();
this.template.addEventListener('notification', this.handleNotification.bind(this));
}
For components outside template:
this.addEventListener('notification', this.handleNotification.bind(this));
Get reference to component Use Event.Target:
who dispatched Event
handleChange(evt) {
console.log('Current value of the input: ' + evt.target.value);
}
Communicate across DOM Using Lightning Messaging Service (LMS):
To communicate between components in a single Lightning page or across multiple pages,
not restricted to a single page. Any component in a Lightning Experience application that
listens for events on a message channel updates when it receives a message
1. Declare a message channel using the LightningMessageChannel metadata type.
2. Publish a message using the publish() function from the
@salesforce/messageChannel module.
3. Subscribe and unsubscribe to a message using the subscribe() and unsubscribe()
functions from the @salesforce/messageChannel module.
Using PubSub:
If containers that don’t support Lightning Messaging Service, use the pubsub module.
Get Data With This is reactive, which is built on LDS. Wire adapter is one of lightning/ui*Api modules.
wire service – Get import { LightningElement, api, wire } from 'lwc';
record data
import { getRecord } from 'lightning/uiRecordApi';
import ACCOUNT_NAME_FIELD from '@salesforce/schema/Account.Name'; 8
export default class Record extends LightningElement {
@api recordId;
@wire(getRecord, { recordId: '$recordId',
fields: [ACCOUNT_NAME_FIELD]})
record;
}
Handle Errors Using LDS wire adapters means it uses Async JavaScript
connectedCallback() {
@wire(getApexMethod)
console.log("first");
wiredContacts({ error, data }) {
setTimeout(() => {
try { if (data) {
try {
throw new Error("some error");
// handle result
console.log("second"); } catch(e) {
} catch(e) { // error when handling result
console.log("error"); }
} } else if (error) {
}, 1000); // error with value provisioning
}
console.log("third");
}
}
Call Apex Method import apexMethodName from '@salesforce/apex/Namespace.Classname.apexMethodReference';
public with sharing class ContactController {
@AuraEnabled(cacheable=true)
public static List<Contact> getContactList() {
return [SELECT Id, Name FROM Contact
WHERE Picture__c != null LIMIT 10];
}
}
Wiring a Apex method:
import apexMethod from '@salesforce/apex/Namespace.Classname.apexMethod';
@wire(apexMethod, { apexMethodParams })
propertyOrFunction;
async handleLoad() {
Call Apex Methods Imperatively:
try {
-When cacheable=true omitted this.contacts = await getContactList();
-To control when invocation occurs this.error = undefined;
-Work with objects where UI API not supported } catch (error) {
this.contacts = undefined;
-Calling method that doesn’t extend LightningElement
this.error = error;
}}
Wire a Apex method with dynamic parameter:
@wire(findContacts, { searchKey: '$searchKey' })
contacts;
Refresh cache using: notifyRecordUpdateAvailable(recordIds)
Import Objects and Fields from @salesforce/schema
getSObjectValue(sobject, fieldApiName);
9
Refresh Ability to sync data without refreshing entire page use RefreshView API and lightning/refresh module.
Component
Direct navigation
Reference across Dynamic
to component by
namespaces Components
name
DESIGN CONSIDERATIONS
UI level Considerations
• Improve performance with Client-side using LDS and cache Apex methods [@AuraEnabled(cacheable=true)]
• Try leveraging pagination on front-end using JavaScript Array.slice() function rather than bringing huge data on UI.
• To import Object and field reference use static schema @salesforce/schema rather than dynamic one.
Data Retrieval Considerations
• Reference When making SELECT query, specify those fields which are necessary
• LIMIT the number of rows returned
• Lazy loading data rather than retrieving all during page load (using offset)
• To retrieve metadata, list, picklist values use UI API functions
Recommendations for server calls
• Consider making server calls when no other options are available.
• Consider reusing same data between components rather than making separate calls.
• Try using client-side filtration using JavaScript functions rather than making separate server calls
11
• Use continuation for long running request to external web service.
• To update records, use imperative Apex call or use UI-API methods
EVENT COMMUNICATIONS
• Use payload for EventTarget.dispatchEvent() - primitive data or copy of data to a new object
• bubbles:true and composed:true are not recommended as they bubble up entire DOM tree, across shadow boundary
• Consider using LMS over pubsub
• Don’t add property into event.detail to communicate data in same shadow tree.
• Don’t forget to remove event listener in disconnectedCallback() lifecycle hook
SECURITY CONSIDERATIONS
Coding Recommendations:
• Use platformResourceLoader module to import 3rd party JavaScript or CSS library
• Avoiding ClickJacking Vulnerability - Avoid using "position: fixed" or high z-index value or negative values at margins
• Never use inline css in html
connectedCallback() {
• Restrict use of innerHTML window.addEventListener('test', this.handleTest.bind(this));
• Prevent event listeners from leaking memory // ^ Event listener will leak.
}
Tools Recommendations:
• ESLint
• Evaluate JavaScript in Lightning Web Security Console
• Lookup distortion details in LWS Distortion Viewer
References
https://developer.salesforce.com/docs/component-library/documentation/lwc
My Dreamforce Session LWC 20-20: 20 Tips in 20 Minutes
Author
Santanu Boral
Salesforce MVP Hall of Fame, 37x certified Professional, Dreamforce 2022 Speaker, Blogger.
Blog: https://santanuboral.blogspot.com/
Date: 29th June 2024
Thank
You
12