Skip to main content

SF-9003 · Concept · Easy

Explain the @api, @track, and @wire decorators in LWC.

✓ Verified by Vikas Singhal · Last reviewed 5/17/2026 · Updated for Spring '26

LWC ships three decorators from the lwc module: @api, @track, and @wire. Each one tells the framework to treat a class member specially.

@api — make a property or method public

@api declares a property or method as part of the component’s public surface. Parents can read, write, or call it; everything else stays private to the component.

import { LightningElement, api } from 'lwc';

export default class ContactCard extends LightningElement {
    @api recordId;          // parent sets <c-contact-card record-id="003..."></c-contact-card>
    @api variant = 'base';  // default value
    @api refresh() {        // public method — parent can call this.template.querySelector('c-contact-card').refresh()
        // ...
    }
}

Two rules that trip people up:

  • Property names are kebab-cased in HTML, camelCased in JS. recordIdrecord-id.
  • Public properties are reactive by default. When the parent changes the value, the child re-renders.

@track — watch deep mutations on objects and arrays

Since LWC API version 49 (Winter ‘21), primitive fields are reactive without @track. Reassign a string or number and the template re-renders. But the framework only observes shallow changes on objects and arrays — assigning a new value to the field, not mutating its internals.

import { LightningElement, track } from 'lwc';

export default class TodoList extends LightningElement {
    items = ['buy milk'];      // reactive on reassignment only
    @track filters = {         // reactive on deep mutation too
        showCompleted: false,
        priority: 'high'
    };

    addItem(name) {
        this.items = [...this.items, name];  // reassignment — works without @track
    }

    togglePriority() {
        this.filters.priority = 'low';        // deep mutation — needs @track
    }
}

The modern convention is to prefer immutable updates (spread, map, filter) over @track. You rarely need the decorator in new code.

@wire — subscribe to a reactive data adapter

@wire connects a property or method to a wire adapter — a function that pushes a stream of { data, error } values. The framework manages caching, refresh, and reactive parameters for you.

import { LightningElement, wire, api } from 'lwc';
import { getRecord } from 'lightning/uiRecordApi';

const FIELDS = ['Contact.Name', 'Contact.Email'];

export default class ContactCard extends LightningElement {
    @api recordId;

    @wire(getRecord, { recordId: '$recordId', fields: FIELDS })
    contact;   // contact.data | contact.error

    get name()  { return this.contact?.data?.fields?.Name?.value; }
    get email() { return this.contact?.data?.fields?.Email?.value; }
}

The $ prefix on $recordId marks the parameter as reactive — change recordId and the wire re-runs.

Quick comparison

DecoratorPurposeReactive?
@apiExpose property/method to parentYes — parent updates trigger re-render
@trackObserve deep object/array mutationsYes — required only for deep changes
@wireSubscribe to a data adapterYes — reactive parameters trigger re-fetch

What interviewers are listening for

A common follow-up: “Do I always need @track for arrays?” The honest answer is no — and saying so demonstrates you’ve kept up with API version changes since Winter ‘21. Mention that the idiomatic LWC pattern is immutable updates, and you’ve separated yourself from candidates copy-pasting decorators from older tutorials.

Verified against: LWC Developer Guide — Reactivity, Decorators reference. Last reviewed 2026-05-17 for Spring ‘26 release.