
This tutorial explains how to build and structure Lightning Web Components (LWC) inside LightningStudio (Salesforce development environment), focusing on the two most important concepts for any LWC developer: Components and Attributes (public properties exposed via @api). You’ll learn file structure, how to create components, pass attributes between parent and child components, use data binding, and follow LWC best practices.
What is a Lightning Web Component?
A Lightning Web Component (LWC) is a modern, standards-based UI building block for Salesforce. Each component encapsulates HTML (template), JavaScript (logic), and optional CSS (styles) plus a configuration file (.js-meta.xml) that defines metadata and component visibility.
Components are reusable — you compose complex UI by nesting components, passing data via attributes, and communicating with events.
Watch Our Video Tutorial
LightningStudio is a developer-friendly workspace (Cloud IDE or local Studio plugin). Typical steps:
- Create a new LWC component (right-click → New → Lightning Web Component)
- Edit
.html,.js, and.cssfiles - Configure
.js-meta.xmlfor target (record page / app / home) - Deploy to scratch org / sandbox or preview locally (if supported)
- Test interactions and attributes
Note: The exact UI of LightningStudio may vary. This guide focuses on LWC concepts that are the same across editors.
Component File Structure (Example)
When you create myCard component, LightningStudio generates:
myCard/ myCard.html <-- template (markup) myCard.js <-- component logic myCard.css <-- component styles (optional) myCard.js-meta.xml <-- metadata (where component can be used)
myCard.html (template)
<template> <div> <h2>{title}</h2> <slot></slot> </div> </template> myCard.js (JavaScript)
import { LightningElement, api } from 'lwc'; export default class MyCard extends LightningElement { @api title = 'Default Title'; // public attribute }
myCard.js-meta.xml (metadata)
<?xml version="1.0" encoding="UTF-8"?> <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata"> <apiVersion>57.0</apiVersion> <isExposed>true</isExposed> <targets> <target>lightning__AppPage</target> <target>lightning__RecordPage</target> </targets> </LightningComponentBundle>
What Are Attributes in LWC?
In LWC, attributes typically mean HTML-like attributes used to pass values to components. On the JavaScript side these map to public properties decorated with @api.
Key points:
@apimarks a property as public — it can be set by a parent component.- Public properties are reactive — when changed by the parent, the child re-renders.
- Attributes passed in markup are converted to strings by HTML — LWC converts or parses where appropriate.
- Boolean attributes and absence/presence nuances exist (see examples below).
Passing Data: Parent → Child
Parent components set child attributes in the child tag. Example:
childComponent.js
import { LightningElement, api } from 'lwc'; export default class ChildComponent extends LightningElement { @api recordId; // public string @api showHeader = true; // public boolean (default true) } parentComponent.html
<template> <c-child-component record-id={currentRecordId} show-header={showHeader}></c-child-component> </template> Important: Attribute names in markup use kebab-case (dash-case) while JS properties use camelCase. The framework maps record-id → recordId, show-header → showHeader.
Child → Parent Communication (Events)
Attributes are one-way (parent → child). To send data up, child components dispatch events:
// child.js this.dispatchEvent(new CustomEvent('saved', { detail: { id: this.recordId } })); // parent.html <c-child-component></c-child-component> // parent.js handleSaved(event) { const id = event.detail.id; }
Detailed Examples: Attribute Types & Behavior
1) String attribute
// child.js import { LightningElement, api } from 'lwc'; export default class Greeting extends LightningElement { @api name = 'Guest'; } <!-- parent.html --> <c-greeting name="Amit"></c-greeting> <!-- OR using JS property binding --> <c-greeting name="{userName}"></c-greeting> 2) Boolean attribute
HTML attributes are strings. To pass boolean true/false reliably, bind to JS boolean or use presence rules.
<!-- parent.html --> <c-child show-header={isHeaderVisible}></c-child> // parent.js isHeaderVisible = true; // boolean
3) Object / Array
Pass via property binding (not static attributes):
<c-child items="{itemsList}"></c-child> // parent.js itemsList = [{id:1, name:'A'}, {id:2, name:'B'}];
Slots & Default Content
Slots let you pass HTML content into child components (markup content), useful for building layout components:
<!-- myCard.html --> <template> <div> <h2>{title}</h2> <slot>Default content if none provided</slot> </div> </template> <!-- parent usage --> <c-my-card title="Welcome"> <p>Custom body provided by parent</p> </c-my-card>
Type Conversion & Edge Cases
Because HTML attributes are strings, be careful with numbers/booleans passed as static literals. Always prefer property binding with curly braces ({}) to pass typed data from parent component JS.
Example:count="10" (string) vs count={countValue} (number when countValue is a number).
Best Practices
- Use
@apifor all properties that should be configurable by parent components. - Favor property binding (
{}) over static string attributes for non-string data. - Use descriptive property names and kebab-case in markup.
- Make attributes immutable where possible — prefer passing new object references instead of mutating children state.
- Validate inputs inside child components (defensive coding).
- Document public attributes in component README or metadata comments.
Common Mistakes & How to Fix Them
| Problem | Cause | Fix |
|---|---|---|
| Child not updating when parent changes | Mutating parent array/object instead of assigning new reference | Use spread or new object: this.items = [...this.items] |
| Boolean attribute appears as string | Passed as static attribute: hidden="false" | Bind to boolean property: hidden={isHidden} |
| Event not received by parent | CustomEvent not configured with composed:true (shadow DOM) | Dispatch with new CustomEvent('name', { detail, bubbles:true, composed:true }) |
Deploying from LightningStudio
- Save component files in your Salesforce DX project folder (force-app/main/default/lwc/...)
- Open Terminal in LightningStudio
- Authorize org:
sfdx force:auth:web:login -a myOrg - Deploy component:
sfdx force:source:deploy -p force-app/main/default/lwc/myCard - Add component to Lightning App Builder or record page (if exposed via meta)
If LightningStudio provides a GUI deploy, you can use that for one-click deployment. Always test in a sandbox first.
Frequently Asked Questions (FAQ)
Conclusion
More SFDC Resources
Start your SFMC journey today — join our Live Training
Need help? Chat with us on WhatsApp anytime.
Learn. Practice. Get Certified. Succeed with Peoplewoo Skills.
