subscribe our youtube channel popup

Navigating to a URL-Addressable Lightning Web Component in Salesforce

Lightning Web Components (LWC) have revolutionized how Salesforce developers build modern, fast, and reusable UI components. With one of the platform enhancements(Summer-24), LWCs can now be made URL-addressable without needing to wrap them inside an Aura component – an exciting shift for developers looking to simplify navigation and state management in their applications. Join us to learn about Navigating to a URL-Addressable Lightning Web Component in Salesforce.

In this post, we’ll explore what it means to make a Lightning Web Component URL-addressable, how to implement it, and walk through a real-world example to understand its practical value.

What Is a URL-Addressable Component?

A URL-addressable component is one that can be navigated to directly via a URL, just like a webpage. In Salesforce, traditionally, if you wanted to access an LWC via URL, you had to embed it inside an Aura component and register that Aura component with lightning__AppPage or other targets. This approach added unnecessary complexity.

Now, with the introduction of the lightning__UrlAddressable target, you can register your LWC directly and navigate to it using the Lightning Navigation Service.

How this feature works

To make your component URL-addressable:

  • Set isExposed to true in the component’s .js-meta.xml file.
  • Include the lightning__UrlAddressable target.
  • Use Lightning Navigation (NavigationMixin) to navigate to the component.
  • Use CurrentPageReference to read state parameters passed in the URL.

Here’s how the .js-meta.xml looks:

<?xml version="1.0" encoding="UTF-8" ?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>59.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__UrlAddressable</target>
    </targets>
</LightningComponentBundle>

This tells Salesforce that your component can be accessed directly through a URL.

Example: Navigate from a Product List to Product Details Using URL Parameters

In this example we’ll build following:

  • Create an Apex class ProductController that returns a list of some products.
  • Use @wire in the productList LWC to call the Apex method.
  • Keep the productDetails component to handle navigation and state.

1. Apex Controller: ProductController.cls

public with sharing class ProductController {
    @AuraEnabled(cacheable=true)
    public static List<Product2> getProducts() {
        return [
            SELECT Id, Name 
            FROM Product2
            LIMIT 10
        ];
    }
}

2. Let’s create LWC component name called productList

productList.Html

<template>
    <lightning-card title="Product List From Apex">
        <template if:true={products}>
            <ul>
                <template for:each={products} for:item="product">
                    <li key={product.Id}>
                        {product.Name}
                        <lightning-button 
                            label="View Details"
                            onclick={handleViewDetails}
                            data-id={product.Id}
                            class="slds-m-left_small">
                        </lightning-button>
                    </li>
                </template>
            </ul>
        </template>
        <template if:true={error}>
            <p class="slds-text-color_error">Error: {error}</p>
        </template>
    </lightning-card>
</template>

productList.js

import { LightningElement, wire } from 'lwc';
import getProducts from '@salesforce/apex/ProductController.getProducts';
import { NavigationMixin } from 'lightning/navigation';
export default class ProductList extends NavigationMixin(LightningElement) {
    products;
    error;
    @wire(getProducts)
    wiredProducts({ error, data }) {
        if (data) {
            this.products = data;
            this.error = undefined;
        } else if (error) {
            this.error = error.body.message;
            this.products = undefined;
        }
    }

    handleViewDetails(event) {
        const productId = event.target.dataset.id;
        this[NavigationMixin.Navigate]({
            type: 'standard__component',
            attributes: {
                componentName: 'c__productDetails'
            },
            state: {
                c__productId: productId
            }
        });
    }
}

productList.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>59.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>

productList component will look like the below screenshot once it is placed on the Home page.

productDetails LWC component:

Now create a new LWC component productDetails. This will be the URL-addressable component that accepts productId from the URL.

productDetails.js 

import { LightningElement, wire } from 'lwc';
import { CurrentPageReference } from 'lightning/navigation';
import getProductById from '@salesforce/apex/ProductController.getProductById';
export default class ProductDetails extends LightningElement {
    productId;
    product2;
    error;
    @wire(CurrentPageReference)
    getStateParameters(currentPageReference) {
        if (currentPageReference) {
            this.productId = currentPageReference.state.c__productId;
        }
    }
    @wire(getProductById, { productId: '$productId' })
    wiredProduct({ error, data }) {
        if (data) {
            this.product2 = data;
            this.error = undefined;
        } else if (error) {
            this.error = error.body.message;
            this.product2 = undefined;
        }
    }
}

productDetails.html

<template>
    <lightning-card title="Product Details">
        <template if:true={product2}>
            <p><strong>Name:</strong> {product2.Name}</p>
            <p><strong>ID:</strong> {product2.Id}</p>
        </template>
        <template if:true={error}>
            <p class="slds-text-color_error">Error: {error}</p>
        </template>
    </lightning-card>
</template>

Add this below method to ProductController.cls:

@AuraEnabled(cacheable=true)
public static Product2 getProductById(String productId) {
    return [
        SELECT Id, Name 
        FROM Product2
        WHERE Id = :productId
        LIMIT 1
    ];
}

We have completed the implementation of two components. There is no need to place the second component on any Lightning page.

Test the Implementation: 

  • In the first component, you will see a “View Details” button for each product in the product list. Simply click on it.
  • The URL addressable target will generate a URL like:

c__productDetails?c__productId=01t5g000003kNFBAA2 (where 01t5g000003kNFBAA2 is the ID of the product that was clicked).

  • You will be redirected to the Product Details page, which displays the product name and ID fetched from the Apex controller.

Final Thoughts

The ability to create URL-addressable Lightning Web Components is a powerful feature that aligns LWC development more closely with modern web application practices. Whether you’re building an internal tool or a managed package, it allows for better navigation, state management, and deep linking within your application. No longer having to wrap an LWC in an Aura component just to make it navigable is a huge productivity boost. Start using this feature to streamline your user experience and make your components more accessible and maintainable. It’s one more step toward cleaner, more scalable Lightning apps. Happy Coding 🙂

Satyam parasa
Satyam parasa

Satyam Parasa is a Salesforce and Mobile application developer. Passionate about learning new technologies, he is the founder of Flutterant.com, where he shares his knowledge and insights.

Articles: 44

Leave a Reply

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