Using @api Properties Without Default Values in Parent Templates
“An unset @api property is undefined, and undefined breaks your template.”
What Happened
Created a reusable data display component for Delivery Hub with several @api properties. The parent component conditionally passed values. When a property wasn't set, it was undefined — and my template's .length call, .map() call, and string concatenation all blew up. The component rendered a blank white box. No error in the console because LWC swallows template expression errors silently.
The Wrong Way
// dataCard.js
import { LightningElement, api } from 'lwc';
export default class DataCard extends LightningElement {
@api records; // undefined if parent doesn't pass it
@api title; // undefined if parent doesn't pass it
get recordCount() {
return this.records.length; // TypeError if records is undefined
}
get displayTitle() {
return this.title.toUpperCase(); // TypeError if title is undefined
}
}
<!-- parent.html - sometimes doesn't pass records -->
<template>
<c-data-card title="My Records"></c-data-card>
<!-- records not passed, component silently breaks -->
</template>The Right Way
// dataCard.js
import { LightningElement, api } from 'lwc';
export default class DataCard extends LightningElement {
@api records = []; // Safe default: empty array
@api title = ''; // Safe default: empty string
get recordCount() {
return this.records?.length ?? 0; // Belt and suspenders
}
get hasRecords() {
return this.records && this.records.length > 0;
}
get displayTitle() {
return this.title ? this.title.toUpperCase() : 'Untitled';
}
}
<!-- dataCard.html - guard with if:true -->
<template>
<h2>{displayTitle}</h2>
<template if:true={hasRecords}>
<template for:each={records} for:item="record">
<p key={record.Id}>{record.Name}</p>
</template>
</template>
<template if:false={hasRecords}>
<p>No records found.</p>
</template>
</template>The Lesson
Always give @api properties safe default values. Guard template expressions with null checks. LWC fails silently on template errors — you'll just see a blank component.
Enjoyed this? Get more like it.
Glen's Musings — AI, investing, and building things. Occasional. Free.
More LWC Mistakes
Mixing Wire and Imperative Apex Calls for the Same Data
Pick one: reactive wire or imperative call. Mixing them creates ghost data.
Read moreRookieCalling querySelector Before the Component Renders
The DOM doesn't exist in connectedCallback. Stop looking for it there.
Read morePainfulMutating Objects Without Triggering Reactivity
LWC tracks property assignment, not deep object mutations.
Read more