Lightning Web Components (LWC): A Complete Practical Guide

SALESFORCE Aug 19, 2026 0 comments 9 Minutes Read
Vaibhav Sharma By Vaibhav Sharma
Lightning Web Components (LWC): A Complete Practical Guide
Last updated: 20 October 2026

You can learn LWC syntax in an afternoon, but what actually takes longer is knowing which of four ways to pass data between components, why renderedCallback keeps firing, and when @wire will quietly serve you stale data.

This guide covers the framework properly, with code you can paste into a scratch org and the current details most LWC content still hasn’t caught up with.

Quick Answer: LWC is Salesforce’s modern UI framework, built on web standards rather than a proprietary abstraction. Three files per component. Use @wire for displaying data, imperative Apex for doing things. Pass data down with @api, up with CustomEvent and sideways with Lightning Message Service – not the old pub/sub module. Guard renderedCallback and know that Lightning Web Security has replaced Locker Service.

What Are Lightning Web Components?

Lightning Web Components are Salesforce’s UI framework, built on native web standards, Web Components, custom elements, shadow DOM, and modern JavaScript. Where Aura wrapped everything in a proprietary layer, LWC leans on what browsers already do, which is why it’s faster and why what you learn transfers to any modern JavaScript work.

  • Why LWC Replaced Aura: Browsers caught up; Aura existed because the web platform lacked components, modules, and templating in 2014. Once browsers gained those natively, a proprietary framework became overhead rather than an advantage.
  • Aura’s Status: Still supported, not deprecated but no longer receiving meaningful investment. Build new work in LWC. See LWC vs Aura vs Visualforce.

Component Anatomy and Lifecycle

Diagram showing the three LWC files - HTML template, JavaScript controller and meta XML config - and the five lifecycle hooks in the order they fire

 

A Minimal Component:

 

The meta XML is not optional boilerplate; if your component doesn’t appear in Lightning App Builder, isExposed or targets is almost always why. Set apiVersion to the API version your org runs. Winter ’27 is API 68.0, and a version newer than your org supports won’t deploy.

The hook that causes the most trouble

renderedCallback() fires after every render, not just the first. Change a reactive property inside it, and you’ve built an infinite loop:

 

Decorators and Reactivity

Three decorators and the rules changed at Spring ’20 in a way plenty of tutorials still get wrong.

@api makes a property public so a parent can set it; public properties are reactive by default.

@track is mostly unnecessary now. Since Spring ’20, all fields are reactive automatically. You only need @track when you mutate an object’s internal property or an array’s contents rather than reassigning the whole thing:

 

  • Prefer Reassignment Over Mutation: It’s cleaner, it works without @track, and it avoids a class of bug that’s genuinely hard to spot.

@wire connects a property or function to a Salesforce data service.

Have an LWC Project in Mind?

Let us know what you’re building, improving, or troubleshooting, and our Salesforce experts can help you determine the right technical approach.

Talk to Our Salesforce Experts →

 

Getting Data: @wire vs Imperative Apex

Comparison of the wire service and imperative Apex calls, showing when each is appropriate

 

@wire – reactive and cached:

 

The $ prefix makes the parameter reactive – change the industry and the wire re-fires automatically.

Imperative – you control it:

 

The Apex Side Matters: A method is only wireable if it’s marked cacheable=true:

 

And cacheable=true means it cannot perform DML, so any save, update, or delete must be a separate, non-cacheable method called imperatively.

Refreshing Stale Data

Wired Apex results come from a client-side cache, and Salesforce doesn’t guarantee how long that cache lasts. When you know the data has changed, refresh it yourself: call refreshApex() with the value your @wire provided, and after an imperative Apex save, call notifyRecordUpdateAvailable() so Lightning Data Service reloads those records everywhere they’re shown.

 

  • Don’t forget Lightning Data Service: For single-record work, getRecord and updateRecord from lightning/uiRecordApi need no Apex at all, respect FLS automatically, and share a cache across components:

 

Related: Apex programming guide · SOQL guide

Component Communication

which method to use for parent-to-child, child-to-parent, sibling and cross-page component communication

Table showing which communication method to use for parent-to-child, child-to-parent, sibling, and cross-page component communication

Parent to child – A public property:

 

Child to parent – a CustomEvent:

Name events the way Salesforce recommends: all lowercase, no spaces, underscores between words (account_selected), and never start the name with “on”. The handler attribute in the parent is “on” plus the event name, so an event called onselect would need ononselect. An event dispatched with uppercase letters, like accountSelected, can’t be handled with an on… attribute in the template, which costs people an hour the first time.

 

Sibling Or Unrelated – Lightning Message Service:

 

LMS is the supported answer, and it works across LWC, Aura, and Visualforce on the same page. The old pubsub module was always a sample pattern rather than a supported API – if you have it in your org, migrate.

The common mistake is over-engineering; if a public property would do, use a public property.

Navigation

 

NavigationMixin works across Lightning Experience, Experience Cloud, and the mobile app – which hardcoded URLs do not.

Testing With Jest

Jest is the standard, and LWC testing is genuinely straightforward once the setup exists. This test is for the @wire version of AccountList from the “Getting Data” section. Its template reads the wired result from accounts.data:

 

 

 

Four things that trip people up:

  • Always clean up in afterEach: Leftover DOM between tests causes failures that look random.
  • await Promise.resolve() before asserting: LWC renders asynchronously; assert too early, and the DOM isn’t there yet.
  • Query through shadowRoot: Components are encapsulated – document.querySelector won’t find inside them.
  • Only public properties can be set from a test: element.someField = … works only for @api properties. For wired data, mock the wire and call .emit(), as in the test above.

Jest tests aren’t counted in your 75% Apex coverage and aren’t required to deploy. That’s exactly why most orgs have none and why the ones that do have noticeably fewer front-end regressions.

Related: Salesforce DevOps and CI/CD

Lightning Web Security

Lightning Web Security (LWS) is the current security architecture for Lightning components. It has been on by default in every org created since Winter ’23, and since Summer ’23 it has been generally available in all orgs for both Lightning web components and Aura components. Lightning Locker (formerly Locker Service) is still maintained but no longer enhanced, and older orgs may still be running it.

The practical difference: Locker restricted access to standard JavaScript APIs fairly aggressively. LWS is less restrictive, permits more standard JavaScript, and gives better third-party library support – while still enforcing namespace isolation between components.

  • What It Means For You: Libraries that failed under Locker often work under LWS, so if you shelved a third-party library, re-test it. To check or switch your org, go to Setup → Session Settings → “Use Lightning Web Security for Lightning web components and Aura components”. Test in a sandbox first, and keep “Enable Stricter Content Security Policy” on, because LWS relies on it.

Performance Patterns

  • Prefer @wire Where It Fits: Platform caching means fewer server round trips.
  • Use Lightning Data Service for single-record reads and writes – shared cache, no Apex.
  • Never Query Inside A Loop In Your Apex Controller: The LWC will look slow when the problem is server-side. See governor limits.
  • Guard renderedCallback.
  • Use lightning-datatable: Rather than building your own table. It comes with keyboard navigation and screen-reader support, and with enable-infinite-loading and an onloadmore handler you can load rows in batches instead of all at once.
  • Render on demand with lwc: if so hidden components aren’t created until they’re needed. The older if:true and if:false directives are legacy and no longer recommended.
  • Debounce user input before firing server calls – a keystroke-per-query search box is the classic mistake.

 

 

Where LWC Runs

  • Lightning Experience: record pages, app pages, home pages, Quick Actions.
  • Experience Cloud: with a caveat. LWR sites support LWC natively; older Aura-based sites have restrictions. Check which template your site uses before promising a component will work.
  • Mobile: via the Salesforce mobile app or Mobile Publisher. Design for touch and test on a real device; the desktop layout rarely survives contact with a phone.
  • Outside Salesforce: LWC Open Source runs anywhere JavaScript does, though the base components and platform services don’t come with it.

Related: Salesforce mobile app development · Experience Cloud

Turn LWC Problems Into Better Experiences

Get expert support for LWC development, performance optimization, component modernization, and Salesforce front-end engineering.

Visit Our Salesforce Development Services →

Common LWC Mistakes

  1. Not guarding renderedCallback – Infinite re-render loops
  2. Using @track unnecessarily – Reactivity has been automatic since Spring ’20
  3. Camel-Case Event Names – onmyEvent never binds
  4. Reaching for LMS when a public property would do
  5. Forgetting cacheable=true on wired Apex methods
  6. Attempting DML In A Cacheable Method – it will fail
  7. Missing isExposed Or Targets in the meta XML
  8. Querying the DOM outside shadowRoot
  9. No Jest Tests, because nothing forces you to write them
  10. Hardcoded URLs instead of NavigationMixin
  11. Ignoring error On A Wired Property – Silent failures
  12. Building Custom Tables instead of using lightning-datatable

Need More Salesforce Development Capacity?

Bring experienced Salesforce developers into your team to build, improve, and maintain LWC applications without slowing down your roadmap.

Hire Salesforce Developers →

Where to Go Next

For the Apex behind your components, see the Apex programming guide and the SOQL guide.

For choosing between frameworks, LWC vs Aura vs Visualforce and Lightning Experience.

For deploying components safely, Salesforce DevOps and sandboxes.

For components on phones, Salesforce mobile app development.

The complete Salesforce development guide is the hub.

When the Front End Is the Symptom

Slow components are usually slow queries; fragile components are usually untested ones. Components nobody will touch are usually components nobody documented.

We’re a certified Salesforce Consulting Partner, and front-end remediation is routine work for our team. Our Salesforce Development Services can help with profiling what’s actually slow, adding Jest coverage, and restructuring components so the next developer can change them safely.

 

FAQs

Salesforce’s modern UI framework, built on native web standards – Web Components, custom elements, shadow DOM, and modern JavaScript. Each component is three files: an HTML template, a JavaScript controller, and a meta XML configuration file. LWC replaced Aura as the recommended framework for new development.

Aura is a proprietary framework built when browsers lacked native component support. LWC uses web standards directly, making it faster and more portable. Aura is still supported but no longer receiving meaningful investment. Build new work in LWC.

Two ways. @wire calls it reactively and caches the result, requiring @AuraEnabled(cacheable=true) on the Apex method. Imperative calls return a Promise and give you control over timing – required for anything performing DML. Use @wire to display data; imperative to do things.

A reactive data mechanism that calls an Apex method or Lightning Data Service function and automatically re-runs when its parameters change. Reactive parameters are prefixed with $. Results are cached by the platform, which reduces server round trips but can mean data isn’t instantly fresh.

Parent to child via @api public properties, child to parent via CustomEvent and dispatchEvent(). Between siblings or unrelated components via Lightning Message Service, which also works across Aura and Visualforce. The old pubsub module was a sample pattern, not a supported API.

Rarely, since Spring ’20, all fields are reactive automatically. You only need @track when mutating an object’s internal property or an array’s contents rather than reassigning the whole value, and reassignment is usually the better pattern anyway.

Because it runs after every render, not just the first. If it modifies a reactive property, that triggers another render, which calls it again. Guard it with a boolean flag so one-time DOM work only happens once.

With Jest, create the element via createElement, append it to the document, await Promise.resolve() so rendering completes, then query through element.shadowRoot. Clean up the DOM in afterEach. Jest tests don’t count toward Apex coverage and aren’t required to deploy, which is why most orgs skip them.

Only in older orgs that haven’t switched. Lightning Web Security has been the default for new orgs since Winter ’23 and is available to all orgs for LWC and Aura; Locker is maintained but not enhanced. LWS permits more standard JavaScript and supports more third-party libraries while keeping components isolated by namespace.

Start by getting comfortable with modern JavaScript (ES6 classes, modules, promises and async/await), because most of LWC is standard JavaScript. Then sign up for a free Salesforce Developer Edition org, complete the Lightning Web Components Basics module on Trailhead and study the LWC Recipes sample app on GitHub. Building one small component each week and deploying it with VS Code and the Salesforce CLI is the fastest way to learn.

Lightning Web Components (LWC) are Salesforce’s UI framework built on native web standards like custom elements, shadow DOM and modern JavaScript. Aura, introduced in 2014, relied on a proprietary framework because browsers did not support components natively then. LWC is faster and lighter because the browser now handles work Aura did in its own layer. Aura is still supported, but new development should use LWC.

The core LWC best practices are to use @wire for reading data and imperative Apex for DML, use Lightning Data Service for single-record work and guard renderedCallback with a flag. Prefer reassigning objects over mutating them with @track, and pass data with @api and CustomEvent before reaching for Lightning Message Service. Use lwc:if instead of if:true and write Jest tests for every component.

Web components are a browser standard, while React is a JavaScript library that renders through a virtual DOM. LWC is built on web components, so it uses native custom elements and shadow DOM with less runtime overhead. React offers a larger ecosystem and more flexibility, LWC offers tighter Salesforce integration. For UIs inside Salesforce, LWC is the recommended choice.

Vaibhav Sharma
Vaibhav Sharma

A Salesforce specialist with over 15 years in the field, Vaibhav Sharma has built his career at the intersection of CRM strategy and enterprise transformation. As the driving force behind Salesforce innovation at DianApps, he architects solutions across Sales Cloud, Service Cloud, and Experience Cloud that turn fragmented customer data into unified growth engines. His work spans a 360-degree perspective in BFSI, healthcare, and retail, where he's known for engineering platforms that don't just go live, they move revenue and retention numbers. Vaibhav's edge lies in reading where Salesforce is headed next, from AI-powered automation, AgentExchange to Agentforce, and translating that foresight into roadmaps enterprise leaders can act on today.

Leave a Comment

Your email address will not be published. Required fields are marked *

Get a free Quote

You will receive a reply in 2 min and your idea is completely safe with us.

8 + 10 = ?
  • In just 2 mins you will get a response
  • Your idea is 100% protected by our Non Disclosure Agreement
Add us as a preferred source on Google »

Looking for something specific?