Salesforce’s LWC (Lightning Web Components) – My First Thoughts

Oh no, another JavaScript framework to learn. At first, it sounds bad. But its a good thing actually. Because being stagnant in coding is bad. Always learning new things is the way to go.

Besides, newer frameworks (especially in JavaScript) show what older frameworks could’ve done better. This is the case with Lightning Web Components (LWC).

Man with Code Background

LWC is Salesforce’s newest iteration of Lightning called Aura. Actually, iteration is an understatement. It’s more like an overhaul. See, Aura is a pretty old framework – I would say at least a decade old. And its the way I learned how to code Salesforce apps. As newer JS frameworks come up, Salesforce decides to up their game.

Enter Lightning Web Components, LWC for short.

I started using LWC for a couple of small components, and I’m liking it a lot. LWC uses web standards and less boilerplate. Just JavaScript, CSS and HTML.

Import / Export

This is probably the biggest change. You can now write modules – just how JS intended it to be.

//importing modules into your component:
import { foo , bar } from "/path/to/lwc-component";
//exporting from your component
export { func1, func2}
//or you can export the entire file
export default class MyClass { .... 

No more clunky adding components in the HTML so you can access the helpers. Or extending components, or including static resources – like how its done with Aura.

This is a big change and I’m really enjoying it.

Component Communication

I happen to like the two way data-binding that existed in Aura. But the new way of passing data between components is not that bad. After a few uses, it’s actually quite neat.

Parent to child is straightforward. Just like other frameworks – using “props” or component attributes.

//parent html:
<c-child some-data={someData}></c-child>
//access it inside the child
export default class Child extends LightningElement {
   @api someData
// marking a property with @api makes it public - and writeable
// now each time parent changes someData - child changes as well

Keep in mind binding is now uni-directional (from Top to Bottom). When we need to pass data upwards, we pass events.

Oh, to fire a child component’s method from the parent, you can simply do something like :


Make sure you make the method public by putting the “@api” on it.

Child to Parent is a little bit different than the example above. We still use attributes, but the attributes are actually custom events that fire.

//inside child JS
sendEmail () {
        const params = {somedata : "hello there..."};
        const evt = new CustomEvent("sendemail", {detail: params });
//note the custom event "sendemail"

The parent component will use the custom event that is dispatched from the child, but will only find it by prefixing an “on” with the event name:

//inside parent HTML:
<c-child onsendemail={sendSingleEmail}

Now you have access to the parameters sent (inside the “detail” property) of the parent function “sendSingleEmail“:

      console.log(JSON.stringify(event.detail) // here is our stuff..

Now, what about if the components are siblings? It would be cumbersome to use the techniques above just correct? And it doesn’t sound right if we have to reorder our components – just to avoid component sibling communication.

Sibling Components – use Lightning Message Service.

This is a component itself used for “publishing” and “subscribing” to data. This will solve our issue with sibling communication. I will not go through the process of how to use this service, you can read about that here:

Then in one component (where you want to receive data), you should be able to do something like below:

subscribe(this.messageContext, YourChannelName, (message) => {
    this.items = message.items;

That callback method in the end with the “message” parameter – can be used for all of your data manipulation in your current component.

Then in the other component, where the data is coming from, you do a “publish“.

publish(this.messageContext, YourChannelName, {items : this.items}); 

Pretty simple right? Of course there is quite a bit that I’m leaving out – but that’s up to you to dig up 😁

Overall, component communication is definitely harder than Aura. It does however remind me a little bit of Redux.

Apex Methods are JavaScript Promises

This one is Salesforce specific – but is still quite nice. Now you can use the “import” statement, for an aura enabled method in your Apex class. An aura enabled method is one that you can call from your front end component.

And if you’re sill lost – Apex is Salesforce’s server side language, while JavaScript Promises are well.. here’s an old article of what they are.

So you can do something like:

import getRecord from '@salesforce/apex/YourClass.getRecord';
//then you can use it like below:
let params = {recordid : id};
    //process result...
    //process error

The imported method from Apex becomes a JS promise – where you can handle it like regular JavaScript. You no longer have to muck with “$A.enqueueAction(action)” like before.

The only thing I don’t like is when you want to use multiple methods – you have to import them one at a time. I’m not sure if you can import all aura methods of a class. Maybe in future releases.


Not a Templating language like Liquid or Handlebars, just the template tag in HTML. Yes – LWC is composed of all template tags for logic in HTML.

I wouldn’t say it’s the most elegant code, but I’m getting used to it. Seeing something like:

 <template if:true={hasError}>
     <h3>There's an error</h3>
<template if:false={hasError}>
     //continue application code

It just feels a little weird. But this is not Salesfoce’s fault. This is web standards and that’s the way it has to be.

And that’s about it so far. Like I said, I am enjoying using LWC and learning it at the same time.

I do wish that Salesforce provide better docs. Most of the time I search for something – and it leads to a Github repo. And we’re just supposed to dig through the code to find an answer.

Its your turn.

Have you tried LWC? What do you think? Leave your comments below.


Leave a Comment.