Fields, Properties, and Attributes

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.

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.

Don’t use these reserved words for property names.

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 Attribute Property in JavaScript
accesskey accessKey
bgcolor bgColor
colspan colSpan
contenteditable contentEditable
crossorigin crossOrigin
datetime dateTime
for htmlFor
formaction formAction
ismap isMap
maxlength maxLength
minlength minLength
novalidate noValidate
readonly readOnly
rowspan rowSpan
tabindex tabIndex
usemap useMap

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

WAI-ARIA States and Properties

Lightning web components reflect these WAI-ARIA states and properties.

ariaActiveDescendant, ariaAtomic, ariaAutoComplete, ariaBusy, ariaChecked, ariaColCount, ariaColIndex, ariaColSpan, ariaControls, ariaCurrent, ariaDescribedBy, ariaDetails, ariaDisabled, ariaErrorMessage, ariaExpanded, ariaFlowTo, ariaHasPopup, ariaHidden, ariaInvalid, ariaKeyShortcuts, ariaLabel, ariaLabelledBy, ariaLevel, ariaLive, ariaModal, ariaMultiLine, ariaMultiSelectable, ariaOrientation, ariaOwns, ariaPlaceholder, ariaPosInSet, ariaPressed, ariaReadOnly, ariaRelevant, ariaRequired, ariaRoleDescription, ariaRowCount, ariaRowIndex, ariaRowSpan, ariaSelected, ariaSetSize, ariaSort, ariaValueMax, ariaValueMin, ariaValueNow, ariaValueText

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().

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.

<template>
    <example-datatable selected-rows="1,2" rows="1,2,3,4"></example-datatable>
</template>

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)
}

Boolean Properties

Boolean attributes on standard HTML Elements are set to true by adding the attribute to the element. The absence of the attribute defaults the attribute to false. Therefore, the default value of an attribute is always false. Lightning web components use the same principle for boolean properties.

Statically Setting a Property

If you want to toggle the value of a boolean property in markup, you must default the value to false.

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

export default class Bool extends LightningElement {
    // Always set the default value for a boolean to false
    @api show = false;
}

Here’s the HTML file.

<!-- bool.html -->
<template>
    <p>show value: {show}</p>
</template>

This parent component consumes example-bool. Because the show attribute isn’t added to <example-bool>, the component displays show value: false.

<!-- parent.html -->
<template>
    <example-bool></example-bool>
</template>

To set the show property to true, add a show attribute with an empty value to the markup. This version of example-parent displays show value: true.

<!-- parent.html -->
<template>
    <example-bool show></example-bool>
</template>

If you set the default value for the show property to be true instead in bool.js, there’s no way to statically toggle the value to false in markup.

Dynamically Setting a Property

To toggle the value if the default property value is true, you can pass down a dynamic computed value from the parent component.

<!-- parent.html -->
<template>
    <example-bool show={computedValue}></example-bool>
</template>

Use a JavaScript getter in parent.js to return the value of {computedValue}.