LWC Javascript Property Introduction

LWC Javascript Property : Declare fields in your component’s JavaScript class. Reference them in your component’s template to dynamically update content.

Field and property are almost interchangeable terms. A component author declares fields in a 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.

Property and attribute are also almost interchangeable terms. Generally speaking, in HTML we talk about attributes, and in JavaScript we talk about properties.

LWC JavaScript Property Names

Property names in JavaScript are in camel case while HTML attribute names are in kebab case (dash-separated) to match HTML standards. For example, a JavaScript property named itemName maps to an HTML attribute named item-name.

Don’t start a property name with these characters.

  • on (for example, onClick)
  • aria (for example, ariaDescribedby)
  • data (for example, dataProperty)

Don’t use these reserved words for property names.

  • slot
  • part
  • is

HTML Attribute Names

HTML attributes in a template cannot contain uppercase characters.

If you have a JavaScript property that starts with an uppercase character, for example @api Upper, and you want to set it via an HTML attribute, you must use special syntax. The uppercase character of the property name is lowercased and prefixed with a hyphen, -upper. The leading hyphen tells the engine that the first alpha character in the attribute name is declared with a leading uppercase character in the JavaScript class.

Access HTML Global Attributes in JavaScript

We don’t recommend using HTML global attributes, which are attributes like class and title that are common to all HTML elements. If you do use a global HTML attribute, decorate it with @api.

Some HTML global attributes don’t follow the Lightning Web Components camel case and kebab case convention. If you create a getter or setter for one of these HTML global attributes, in JavaScript, use the case in this list.

For example, to access the HTML maxlength attribute of textarea in JavaScript, use maxLength. To access the for HTML attribute from JavaScript, use htmlFor.

HTML Global AttributeProperty in JavaScript
accesskeyaccessKey
bgcolorbgColor
colspancolSpan
contenteditablecontentEditable
crossorigincrossOrigin
datetimedateTime
forhtmlFor
formactionformAction
ismapisMap
maxlengthmaxLength
minlengthminLength
novalidatenoValidate
readonlyreadOnly
rowspanrowSpan
tabindextabIndex
usemapuseMap

Web API Properties

Lightning web components reflect the properties of many Web APIs.

Element

Lightning web components reflect these properties of the Element interface.

classList, className, getAttribute, getAttributeNS, getBoundingClientRect, getElementsByClassName, getElementsByTagName, hasAttribute, hasAttributeNS, id, querySelector, querySelectorAll, removeAttribute, removeAttributeNS, setAttributeNS, setAttribute, shadowRoot, slot

EventTarget

Lightning web components reflect these properties of the EventTarget interface.

addEventListener, dispatchEvent, removeEventListener

HTMLElement

Lightning web components reflect these properties of the HTMLElement interface.

accessKeyLabel, contentEditable, dataset, dir, hidden, isContentEditable, lang, offsetHeight, offsetLeft, offsetParent, offsetTop, offsetWidth, title

Node

Lightning web components reflect this property of the Node interface.

isConnected

Reflect JavaScript Properties to HTML Attributes

You can control whether public JavaScript properties appear as attributes in the rendered HTML of a Lightning web component. Allowing properties to appear as attributes is especially important when creating accessible components, because screen readers and other assistive technologies use HTML attributes.

All HTML attributes are reactive by default. When an attribute’s value changes in the component HTML, the component re-renders.

When you take control of an attribute by exposing it as a public property, the attribute no longer appears in the HTML output by default. To pass the value through to the rendered HTML as an attribute (to reflect the property), define a getter and setter for the property and call the setAttribute() method.

You can also perform operations in the setter. Use a private property to hold the computed value. Decorate the private property with @track to make the property reactive. If the property’s value changes, the component re-renders.

This example exposes title as a public property. It converts the title to uppercase and uses the tracked property privateTitle to hold the computed value of the title. The setter calls setAttribute() to reflect the property’s value to the HTML attribute.

// myComponent.js
import { LightningElement, api } from 'lwc';

export default class MyComponent extends LightningElement {
    privateTitle;

    @api
    get title() {
        return this.privateTitle;
    }

    set title(value) {
        this.privateTitle = value.toUpperCase();
        this.setAttribute('title', this.privateTitle);
    }
}
/* parent.html */
<template>
    <example-my-component title="Hover Over the Component to See Me"></example-my-component>
</template>
/* Generated HTML */
<example-my-component title="HOVER OVER THE COMPONENT TO SEE ME">
    <div>Reflecting Attributes Example</div>
</example-my-component>

To make sure that you understand how JavaScript properties reflect to HTML attributes, look at the same code without the call to setAttribute(). The generated HTML doesn’t include the title attribute.

// myComponent.js
import { LightningElement, api } from 'lwc';

export default class MyComponent extends LightningElement {
    privateTitle;

    @api
    get title() {
        return this.privateTitle;
    }

    set title(value) {
        this.privateTitle = value.toUpperCase();
        // this.setAttribute('title', this.privateTitle);
    }
}
/* parent.html */
<template>
    <example-my-component title="Hover Over the Component to See Me"></example-my-component>
</template>
/* Generated HTML */
<example-my-component>
    <div>Reflecting Attributes Example</div>
</example-my-component>

Before you set a value, check if the value has already been set by the consumer.

// myComponent.js
import { LightningElement } from 'lwc';

export default class MyComponent extends LightningElement {

    connectedCallback() {
        const tabindex = this.getAttribute('tabindex');

        // Set the tabindex to 0 if it hasn’t been set by the consumer.
        if (!tabindex) {
            this.setAttribute('tabindex','0');
        }
    }
}

Setting the tabindex using this.setAttribute() results in this markup.

<example-my-component tabindex="0"></example-my-component>

To set these attributes, use setAttribute().

  • for
  • aria-activedescendant
  • aria-controls
  • aria-describedby
  • aria-details
  • aria-errormessage
  • aria-flowto
  • aria-labelledby
  • aria-owns

To hide HTML attributes from the rendered HTML, call removeAttribute().

Manage Attribute Dependencies in a Getter

An attribute in HTML turns into a property assignment in JavaScript. In both cases, the order of assignment is not guaranteed. To check for the existence of other attributes use a getter. Don’t use an @api setter that relies on a value from another @api property.

Use a getter reference in the template (not the @api getter).

Let’s assume we have a datatable component that displays a check mark on selected rows. We have two separate attributes rows and selectedRows, which have a dependency on the other.

Since the order in which the attributes are received isn’t guaranteed, use getters to check the dependency.

export default class Datatatable extends LightningElement {
    @track state = {};

    @api
    get rows() {
        return this.state.rows;
    }

    set rows(value) {
        this.state.rows = value;

        // Check to see if the rows have
        // been marked as selected.
        if (this.state.selectedRows && !this.selectedRowsSet) {
            this.markSelectedRows();
            this.selectedRowsSet = true;
        }
    }

    @api
    get selectedRows() {
         return this.state.selectedRows;
    }

    set selectedRows(value) {
        this.state.selectedRows = value;

        // If rows haven’t been set,
        // then we can't mark anything
        // as selected.
        if (!this.state.rows) {
            this.selectedRowsSet = false;
            return;
        }

        this.markSelectedRows();
    }

    markSelectedRows() {
        // Mark selected rows.
    }
}

Using getters and setters ensures that the public API contract is easily enforced. Don’t change the value of a property that’s annotated with @api.

Getters and Setters

When a component receives data, it performs two basic operations: storing and reacting. In the simplest case, you can declare your @api property and be done.

<template>
    <h1>Greetings, {message}.</h1>
</template>
export default class LightningHello extends LightningElement {
    @api message;
}

However, you probably want to do more interesting things with the data, such as normalizing it or modifying it.

Let’s say you are being passed an array and you have to display the list of items with modified data.

const items = [
    {label : "item1"},
    {label : "item2"},
    {label : "item3"}
 ];

The markup iterates over the array and displays the items. The for:each directive requires a key value for each item in a list.

<template>
    <ul>
        <template for:each = {state.items} for:item = "item">
            <li key={item.key}>
                {item.label}
            </li>
        </template>
    </ul>
</template>

To modify the data to add a value for the key property, use this pattern.

export default class LightningList extends LightningElement {
    @track state = {};
    privateItems = {};

    @api
    get items() {
        return this.privateItems;
    }

    set items(items) {
        this.privateItems = items;

        this.state.items = items.map( item  => {
            return {
               label : item.label ,
               key: generateUniqueId()
            }
        });
    }
}

The original value is stored before the state object is modified for the template.

Normalize data in the setter if something depends on that value at set time, for example, to append a CSS class programmatically on an element. Return the original value in the getter. Normalization can also be done in the getter so that the template has access to a value even if the consumer doesn’t set anything.

@track state = {
    selected : false
};

privateSelected = 'false';

@api
get selected() {
    return this.privateSelected;
}
set selected(value) {
    this.privateSelected = value;
    this.state.selected = normalizeBoolean(value)
}
Scroll to Top