Start tracking your progress
Trailhead Home
Trailhead Home

Create Lightning Web Components

Learning Objectives

After completing this unit, you’ll be able to:

  • Describe the contents of each component file.
  • Create JavaScript methods for a Lightning web component.
  • Use Lifecycle Hooks in component JavaScript.

Some Serious Play Time

Say you want to build a data display element, independent of a specific object in Salesforce. A good example is the productCard component in the ebikes sample repo. Let’s examine that card component, and build our own version from scratch so you can see how it evolves into a full-fledged Lightning web component. You’ll quickly get the basics when you build up the parts of a component in the Lightning Web Components Playground and explore more samples.

A component simply needs a folder and its files with the same name. They’re automatically linked by name and location.

Component files in a folder

All Lightning web components have a namespace that’s separated from the folder name by a hyphen. For example, the markup for the Lightning web component with the folder name app in the default namespace c is <c-app>. You can see this in main.js in the Lightning Web Components Playground.

However, the Salesforce platform doesn’t allow hyphens in the component folder or file names. What if a component’s name has more than one word, like “mycomponent”? You can’t name the folder and files my-component, but we do have a handy solution.

Use camel case to name your component myComponent. Camel case component folder names map to kebab-case in markup. In markup, to reference a component with the folder name myComponent, use <c-my-component>.

For example, the LWC Samples repo has the viewSource folder containing the files for the viewSource component. When the hello component references the viewSource component in HTML, it uses c-view-source.

A Look Into the HTML File

Lightning web component HTML files all include the template tag. The template tag contains the HTML that defines the structure of your component. Let’s look at the HTML for a simplified version of the productCard component from the ebikes repo.

Follow along by pasting these examples in the Lightning Web Components Playground.

  1. Click New to start a new project.
  2. Paste the following into app.html (replacing any existing HTML in the file).
<template>
    <div>
        <div>Name: {name}</div>
        <div>Description: {description}</div>
        <div>Category: {category}</div>
        <div>Material: {material}</div>
        <div>Price: {price}</div>
        <div><img src={pictureUrl}/></div>
    </div>
</template>

The identifiers in the curly braces {} are bound to the fields of the same name in the corresponding JavaScript class.

Here’s a JavaScript file to support this HTML. Paste this into app.js.

import { LightningElement } from 'lwc';
export default class App extends LightningElement {
   name = 'Electra X4';
   description = 'A sweet bike built for comfort.';
   category = 'Mountain';
   material = 'Steel';
   price = '$2,700';
   pictureUrl = 'https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/electrax4.jpg';
}

The Preview now shows a bike with some details. If not, Click Run.

Now let’s say you want to display data, but you know it can take some time to load. You don’t want the user wondering what’s up. You can use if:false and if:true conditional directives within your template to determine which visual elements are rendered.

The following content in the “display” div tag doesn’t appear until the value of ready is true in the HTML file.

<template>
    <div id="waiting" if:false={ready}>Loading…</div>
    <div id="display" if:true={ready}>
        <div>Name: {name}</div>
        <div>Description: {description}</div>
        <div>Category: {category}</div>
        <div>Material: {material}</div>
        <div>Price: {price}</div>
        <div><img src={pictureUrl}/></div>
    </div>
</template>

Here’s some JavaScript to test it in the playground. This holds our data values and sets a 3-second timer. After 3 seconds, the content should appear. (Of course, this is only for testing purposes.)

import { LightningElement } from 'lwc';
export default class App extends LightningElement {
   name = 'Electra X4';
   description = 'A sweet bike built for comfort.';
   category = 'Mountain';
   material = 'Steel';
   price = '$2,700';
   pictureUrl = 'https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/electrax4.jpg';
   ready = false;
   connectedCallback() {
       setTimeout(() => {
           this.ready = true;
       }, 3000);
   }
}

Click Run to see the conditional directive working.

Base Lightning Web Components

Now, you don’t want to build all your components from the ground up. So let’s explore using a base Lightning web component. And of course, there are lots of components, including field types, display controllers, navigation items, and more. All of them are listed in the Component Reference.

Let’s make the details of the bike stand out. To do this, replace the div tags for material and category in the last example with a lightning-badge component. Here's the HTML.

<template>
    <div id="waiting" if:false={ready}>Loading…</div>
    <div id="display" if:true={ready}>
        <div>Name: {name}</div>
        <div>Description: {description}</div>
        <lightning-badge label={material}></lightning-badge>
        <lightning-badge label={category}></lightning-badge>
        <div>Price: {price}</div>
        <div><img src={pictureUrl}/></div>
    </div>
</template>

The words Steel and Mountain appear as badges. It’s that simple.

Lightning badges in use

OK. Let’s look at the JavaScript.

Working with JavaScript

Here’s where you make stuff happen. As you’ve seen so far, JavaScript methods define what to do with input, data, events, changes to state, and more to make your component work.

The JavaScript file for a Lightning web component must include at least this code, where MyComponent is the name you assign your component class.

import { LightningElement } from 'lwc';
export default class MyComponent extends LightningElement {
}

The export statement defines a class that extends the LightningElement class. As a best practice, the name of the class usually matches the file name of the JavaScript class, but it’s not a requirement.

The LWC Module

Lightning Web Components uses modules (built-in modules were introduced in ECMAScript 6) to bundle core functionality and make it accessible to the JavaScript in your component file. The core module for Lightning web components is lwc.

Begin the module with the import statement and specify the functionality of the module that your component uses.

The import statement indicates the JavaScript uses the LightningElement functionality from the lwc module.

// import module elements
import { LightningElement} from 'lwc';
// declare class to expose the component
export default class App extends LightningElement {
    ready = false;
    // use lifecycle hook
    connectedCallback() {
        setTimeout(() => {
            this.ready = true;
        }, 3000);
    }
}
  • LightningElement is the base class for Lightning web components, which allows us to use connectedCallback().
  • The connectedCallback() method is one of our lifecycle hooks. You’ll learn more about lifecycle hooks in the next section. For now, know that the method is triggered when a component is inserted in the document object model (DOM). In this case, it starts the timer.

Lifecycle Hooks

Lightning Web Components provides methods that allow you to “hook” your code up to critical events in a component’s lifecycle. These events include when a component is:

  • Created
  • Added to the DOM
  • Rendered in the browser
  • Encountering errors
  • Removed from the DOM

Respond to any of these lifecycle events using callback methods. For example, the connectedCallback() is invoked when a component is inserted into the DOM. The disconnectedCallback() is invoked when a component is removed from the DOM.

In the JavaScript file we used to test our conditional rendering, we used the connectedCallback() method to automatically execute code when the component is inserted into the DOM. The code waits 3 seconds, then sets ready to true.

import { LightningElement } from 'lwc';
export default class App extends LightningElement {
    ready = false;
    connectedCallback() {
        setTimeout(() => {
            this.ready = true;
        }, 3000);
    }
}
Note

Note

When you use this example in an editor like VS Code, you might see a lint warning "Restricted async operation...." for the setTimeout() function. This warning indicates you’re using an async operation that's often misused; it delays behavior based on time instead of waiting for an event. In this case, setTimeout() is suitable to demonstrate an arbitrary time delay, and the warning should not prevent you from using it.

Also, notice that we used the this keyword. Keyword usage should be familiar if you’ve written JavaScript, and behaves just like it does in other environments. The this keyword in JavaScript refers to the top level of the current context. Here, the context is this class. The connectedCallback() method assigns the value for the top level ready variable. It’s a great example of how Lightning Web Components lets you bring JavaScript features into your development. You can find a link to good information about this in the Resources section.

We’re moving fast and you’ve been able to try out some things. In the next unit, we take a step back and talk more about the environment where the components live.

Decorators

Decorators are often used in JavaScript to modify the behavior of a property or function.

To use a decorator, import it from the lwc module and place it before the property or function.

import { LightningElement, api } from 'lwc';
export default class MyComponent extends LightningElement{
    @api message;
}

You can import multiple decorators, but a single property or function can have only one decorator. For example, a property can’t have @api and @wire decorators.

Examples of Lightning Web Components decorators include:

  • @api: Marks a field as public. Public properties define the API for a component. An owner component that uses the component in its HTML markup can access the component’s public properties. All public properties are reactive, which means that the framework observes the property for changes. When the property’s value changes, the framework reacts and rerenders the component.
    Tip Tip Field and property are almost interchangeable terms. A component author declares fields in a JavaScript class. An instance of the class has properties. To component consumers, fields are properties. In a Lightning web component, only fields that a component author decorates with @api are publicly available to consumers as object properties.
  • @track: Tells the framework to observe changes to the properties of an object or to the elements of an array. If a change occurs, the framework rerenders the component. All fields are reactive. If the value of a field changes and the field is used in a template—or in the getter of a property used in a template—the framework rerenders the component. You don’t need to decorate the field with @track. Use @track only if a field contains an object or an array and if you want the framework to observe changes to the properties of the object or to the elements of the array. If you want to change the value of the whole property, you don’t need to use @track.
    Note Prior to Spring ’20, you had to use @track to mark fields (also known as private properties) as reactive. You’re no longer required to do that. Use @track only to tell the framework to observe changes to the properties of an object or to the elements of an array. Some legacy examples may still use @track where it isn’t needed, but that’s OK because using the decorator doesn’t change the functionality or break the code. For more information, see this release note.
  • @wire: Gives you an easy way to get and bind data from a Salesforce org.

Here’s an example using the @api decorator to render a value from one component (bike) in another component (app). In the component playground, the files look like this: Sample app file structure.

The app component uses the following HTML.

<!-- app.html -->
<template>
<div>
    <c-bike bike={bike}></c-bike>
</div>
</template>

The app component uses the following JavaScript.

// app.js
import { LightningElement } from 'lwc';
export default class App extends LightningElement {
    bike = {
        name: 'Electra X4',
        picture: 'https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/electrax4.jpg'
    };
}

The bike component uses the following HTML.

<!-- bike.html -->
<template>
    <img src={bike.picture} alt="bike picture" />
    <p>{bike.name}</p>
</template>

The bike component uses the following JavaScript.

// bike.js
import { LightningElement, api } from 'lwc';
export default class Bike extends LightningElement {
    @api bike;
}

Try it in the component playground with and without the @api decorator to see the behavior.

Bonus! Try These Components in the Playground

Now that you’re familiar with the component playground, take a little time to experiment with some of the examples in the Lightning Web Components Recipes. Try pasting some of the HTML, JavaScript, and CSS from the examples there into the component playground as a great way to get familiar with core component concepts.

Resources