Real Project Example – Build a Small LWC Dashboard

This post walks through a small dashboard example that combines records, a filter, and a summary card using LWC.

1. Dashboard Requirements

2. Apex Controller


public with sharing class DashboardController {
    @AuraEnabled(cacheable=true)
    public static List getTopAccounts(String industry) {
        String query = 'SELECT Id, Name, AnnualRevenue, Industry FROM Account ' +
                       'WHERE AnnualRevenue != NULL ' +
                       (industry != null ? 'AND Industry = :industry ' : '') +
                       'ORDER BY AnnualRevenue DESC LIMIT 10';
        return Database.query(query);
    }

    @AuraEnabled(cacheable=true)
    public static Map getSummaryMetrics() {
        Map metrics = new Map();
        metrics.put('totalAccounts', [SELECT COUNT() FROM Account]);
        metrics.put('totalRevenue', [SELECT SUM(AnnualRevenue) total FROM Account].get('total'));
        return metrics;
    }
}
  

3. Component JavaScript


import { LightningElement, track, wire } from 'lwc';
import getTopAccounts from '@salesforce/apex/DashboardController.getTopAccounts';
import getSummaryMetrics from '@salesforce/apex/DashboardController.getSummaryMetrics';

export default class AccountDashboard extends LightningElement {
    @track industry = '';
    @track accounts = [];
    @track summary = {};
    @track error;

    @wire(getSummaryMetrics)
    wiredSummary({ error, data }) {
        if (data) {
            this.summary = data;
        } else if (error) {
            this.error = error;
        }
    }

    @wire(getTopAccounts, { industry: '$industry' })
    wiredAccounts({ error, data }) {
        if (data) {
            this.accounts = data;
            this.error = undefined;
        } else if (error) {
            this.error = error;
        }
    }

    handleIndustryChange(event) {
        this.industry = event.target.value;
    }
}
  

4. Component Template


<template>
    <section class="dashboard">
        <div class="summary-cards">
            <div class="summary-card">
                <h3>Accounts</h3>
                <p>{summary.totalAccounts}</p>
            </div>
            <div class="summary-card">
                <h3>Total Revenue</h3>
                <p>{summary.totalRevenue}</p>
            </div>
        </div>

        <div class="filters">
            <lightning-combobox
                label="Industry"
                options={industryOptions}
                value={industry}
                onchange={handleIndustryChange}
            ></lightning-combobox>
        </div>

        <div class="table-container">
            <table class="slds-table slds-table_cell-buffer slds-table_bordered">
                <thead>
                    <tr>
                        <th>Name</th>
                        <th>Industry</th>
                        <th>Annual Revenue</th>
                    </tr>
                </thead>
                <tbody>
                    <template for:each={accounts} for:item="account">
                        <tr key={account.Id}>
                            <td>{account.Name}</td>
                            <td>{account.Industry}</td>
                            <td>{account.AnnualRevenue}</td>
                        </tr>
                    </template>
                </tbody>
            </table>
        </div>

        <template if:true={error}>
            <div class="error">Error loading dashboard</div>
        </template>
    </section>
</template>
  

5. Dashboard Best Practices

Key Takeaways