Overview
The @api decorator marks a property as public, making it accessible from parent components. Public properties enable parent-to-child communication and are reactive by default.
Public properties decorated with @api are reactive. When a parent component changes the value, the child component automatically re-renders.
Basic Usage
Simple Public Property
Expose a property to parent components:
// chartBar.js
import { LightningElement, api } from 'lwc';
export default class ChartBar extends LightningElement {
@api percentage;
get style() {
return `width: ${this.percentage}%`;
}
}
Parent component passes data:
<!-- apiProperty.html -->
<template>
<lightning-input
label="Percentage"
type="number"
value={percentage}
onchange={handlePercentageChange}
></lightning-input>
<c-chart-bar percentage={percentage}></c-chart-bar>
</template>
// apiProperty.js
import { LightningElement } from 'lwc';
export default class ApiProperty extends LightningElement {
percentage = 50;
handlePercentageChange(event) {
this.percentage = event.target.value;
}
}
Source: force-app/main/default/lwc/apiProperty/apiProperty.js:3-9
Multiple Public Properties
A component can expose multiple public properties:
// child.js
import { LightningElement, api } from 'lwc';
export default class Child extends LightningElement {
@api firstName;
@api lastName;
get fullName() {
return `${this.firstName} ${this.lastName}`;
}
}
<!-- child.html -->
<template>
<p>Hello, {fullName}!</p>
</template>
Source: force-app/main/default/lwc/child/child.js:3-10
Getters and Setters
Use @api with getters and setters to add custom logic when properties change:
// todoList.js
import { LightningElement, api } from 'lwc';
export default class TodoList extends LightningElement {
filteredTodos = [];
_todos = [];
priorityFilter = false;
@api
get todos() {
return this._todos;
}
set todos(value) {
this._todos = value;
this.filterTodos();
}
filterTodos() {
if (this.priorityFilter) {
this.filteredTodos = this._todos.filter(
(todo) => todo.priority === true
);
} else {
this.filteredTodos = this._todos;
}
}
}
When using getters and setters with @api, place the decorator before the getter, not the setter.
Source: force-app/main/default/lwc/todoList/todoList.js:14-21
Spreading Properties
Pass multiple properties as an object using the spread syntax:
// apiSpread.js
import { LightningElement } from 'lwc';
export default class ApiSpread extends LightningElement {
props = {
firstName: 'Amy',
lastName: 'Taylor'
};
handleChange(event) {
const field = event.target.name;
if (field === 'firstName') {
this.props = {
firstName: event.target.value,
lastName: this.props.lastName
};
} else if (field === 'lastName') {
this.props = {
firstName: this.props.firstName,
lastName: event.target.value
};
}
}
}
In the template, use the spread operator:
<c-child {...props}></c-child>
Source: force-app/main/default/lwc/apiSpread/apiSpread.js:3-23
Best Practices
- Reactive by default: Public properties automatically trigger re-renders when changed
- Use private fields: Store internal state in private properties (prefixed with
_)
- Immutability: Always create new objects/arrays instead of mutating existing ones
- Validation: Add validation logic in setters before assigning values
- Computed properties: Use getters to derive values from public properties