Skip to main content

How to Build a Custom Record History Component in Salesforce LWC

In plain words: A custom history component allows you to track and display specific data changes on a Salesforce record using a tailored user interface. Instead of relying purely on the standard out-of-the-box Related Lists, building this in Lightning Web Components (LWC) gives you total control over the design, logic, and user experience.

Tracking historical data and field updates is a common requirement in Salesforce development. In this guide, we will walk through building a custom component using Lightning Web Components (LWC) to dynamically fetch and display record data. By the end of this tutorial, you'll have a fully functional template ready to be deployed to your org.

Prerequisites

Before writing the code, ensure your development environment is fully configured:

  • A Salesforce Developer Edition Account or Sandbox Org.
  • The latest Salesforce CLI installed on your machine.
  • Visual Studio Code with the Salesforce Extension Pack.
  • A basic understanding of Lightning Web Components (HTML, CSS, and JavaScript).

Step 1: Set Up the Salesforce Project

First, we need to create a new Salesforce project using the modern Salesforce CLI (sf). Open your terminal or VS Code command prompt and run the following command to generate the project structure:

sf project generate -n MyHistoryComponentProject

Once the project is created, navigate into the new directory:

cd MyHistoryComponentProject
Real-Life Example: We are using the newer sf project generate command instead of the legacy sfdx force:project:create. Salesforce is actively migrating to the unified sf command structure for a cleaner developer experience.

Step 2: Create the Component

Next, scaffold the new Lightning Web Component. We'll name it historyComponent.

sf lightning generate component -n historyComponent -d force-app/main/default/lwc

This generates the essential HTML, JS, and XML files needed to build out the UI.

Step 3: Implement the JavaScript Logic

Open the generated historyComponent.js file. We are going to use the powerful @wire decorator alongside getRecord from the User Interface API to fetch data without writing a single line of Apex.

import { LightningElement, api, wire } from 'lwc';
import { getRecord } from 'lightning/uiRecordApi';

// Define the fields you want to display
const FIELDS = ['Object__c.Field1__c', 'Object__c.Field2__c', 'Object__c.Field3__c'];

export default class HistoryComponent extends LightningElement {
    // Expose the recordId so it can receive data from the record page
    @api recordId;

    // Wire the standard getRecord adapter to fetch data reactively
    @wire(getRecord, { recordId: '$recordId', fields: FIELDS })
    object;

    // Getter to format the returned fields into a clean array for the template
    get objectFields() {
        return this.object.data ? Object.values(this.object.data.fields) : [];
    }
}
Developer Trap: Note the dollar sign ('$recordId') in the wire adapter! This makes the variable reactive. If the record ID changes (or if the component loads before the ID is ready), the wire service will automatically refetch the data. Omitting the dollar sign will cause the wire adapter to fail silently.

Step 4: Create the HTML Markup

Now, let's build the frontend. Open historyComponent.html and use a for:each directive to iterate over the fields we formatted in our JavaScript getter.

<template>
    <div class="container">
        <h1>Record Details & History</h1>
        
        <ul class="field-list">
            <template for:each={objectFields} for:item="field">
                <li key={field.apiName}>
                    <strong>{field.apiName}:</strong> {field.value}
                </li>
            </template>
        </ul>
    </div>
</template>

Step 5: Apply Custom CSS Styling

To make our list look presentable, add the following basic styles to historyComponent.css.

.container {
    padding: 20px;
    background-color: #ffffff;
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}

h1 {
    font-size: 20px;
    font-weight: bold;
    margin-bottom: 12px;
    color: #1f4e79;
}

.field-list {
    list-style-type: none;
    padding: 0;
    margin: 0;
}

.field-list li {
    margin-bottom: 10px;
    font-size: 15px;
    padding-bottom: 6px;
    border-bottom: 1px solid #f3f3f3;
}

Step 6: Deploy to Salesforce

With our code complete, it's time to push it to the org. Use the updated Salesforce CLI deploy command:

sf project deploy start
Configuration Check: Before deploying, make sure your historyComponent.js-meta.xml file has <isExposed>true</isExposed> and targets the lightning__RecordPage so it is visible in the App Builder!

Step 7: Add to a Lightning Record Page

Finally, let's place the component on the actual user interface:

  1. Log into your Salesforce org and navigate to any record of the object you are testing (e.g., Account or your Custom Object).
  2. Click the Gear Icon in the top right and select Edit Page to open the Lightning App Builder.
  3. In the left-hand Components pane, scroll down to the Custom section.
  4. Drag and drop the historyComponent onto your page layout.
  5. Click Save and then Activate to assign the page to your users.
Core Takeaway: LWC combined with the UI API makes fetching and displaying record data incredibly fast and efficient without requiring custom Apex controllers.

Conclusion

Congratulations! You have successfully built and deployed a custom data-tracking component using Salesforce LWC. This foundational setup allows you to surface important fields interactively. You can easily extend this logic later by wiring an Apex controller to query actual History tracking tables (like AccountHistory) if you need a detailed audit trail of old versus new values. Happy coding!