How to Use This Standard

Use this page in sequence when reviewing or authoring LWC code so guidance builds from basics to advanced concerns:

  1. Start with Code Style and Formatting to establish baseline readability.
  2. Move to Code Complexity, especially Return statement patterns, to keep logic maintainable.
  3. Apply Performance Optimization and Component Composition patterns for scalable implementation.
  4. Validate Security and Browser Compatibility before completion.
  5. Finish with API Version Standards and Code Maintenance for long-term upkeep.

Code Style and Formatting

Prettier Compliance

Usage: Use Prettier for code formatting (configured in project).

Guidelines:

  • Run Prettier before committing code
  • Ensure consistent formatting across the codebase
  • Don't disable Prettier unless absolutely necessary

Indentation

Usage: Use 4 spaces for indentation (Prettier default).

Line Length

Guidelines:

  • Keep lines under 100 characters when possible
  • Break long lines appropriately
  • Use proper indentation for continuation

Examples:

// Good: Break long lines appropriately
const result = await this[NavigationMixin.Navigate]({
    type: 'standard__recordPage',
    attributes: {
        recordId: this.recordId,
        actionName: 'view'
    }
});
// Good: Call Apex through a named selector or service (imports at module top in real components)
import getAccounts from '@salesforce/apex/ACME_AccountSelector.getAccounts';

const accounts = await getAccounts();

Code Formatting Best Practices

  • Use Prettier for consistent formatting
  • Keep lines readable (under 100 characters)
  • Use proper indentation
  • Format consistently across the codebase

Code Complexity

Return statement patterns

Optimize for readability and shallow nesting, not for counting return statements.

Guidelines:

  • Use early returns for guard clauses -- Invalid state, missing data, or permissions checks should fail fast at the top of handlers and async functions. This is the default pattern for LWC methods.
  • Multiple exits are acceptable when each return is easy to see and the function remains short enough to follow. If exits multiply or the function grows long, extract helpers rather than forcing a single exit.
  • Prefer one return at the end when several branches all contribute to one final value or outcome and early returns would duplicate setup or obscure how the result is built. This is optional, not a general rule for "complex" functions.

Example: Early returns (guard clauses)

async handleSave() {
    if (!this.recordId) {
        this.showError('Record ID is required');
        return;
    }
    if (!this.isEditable) {
        return;
    }
    await this.persist();
}

Example: Single return (intertwined branching)

Use one exit at the end when nested conditions all assign into the same outcome variable:

get displayTier() {
    let tier;
    if (this.amount > 10000) {
        if (this.segment === 'Enterprise') {
            tier = 'Premium';
        } else {
            tier = 'High value';
        }
    } else {
        tier = 'Standard';
    }
    return tier;
}

Cognitive Complexity Limits

Guidelines:

  • Keep methods simple and focused
  • Refactor complex methods into smaller methods
  • Use early returns and guard clauses to reduce nesting (see Return statement patterns)
  • Avoid deep nesting (max 4 levels)

Examples:

// Bad: Too complex
handleClick() {
    if (this.url) {
        if (this.copyUrl) {
            this.handleCopy();
        } else {
            if (this.newTab) {
                this[NavigationMixin.GenerateUrl]({
                    type: 'standard__webPage',
                    attributes: { url: this.url }
                }).then((url) => {
                    window.open(url, '_blank');
                });
            } else {
                if (REGEX_SALESFORCE.test(this.url)) {
                    this[NavigationMixin.Navigate]({
                        type: 'standard__recordPage',
                        attributes: {
                            recordId: this.url,
                            actionName: 'view'
                        }
                    });
                } else {
                    this[NavigationMixin.Navigate]({
                        type: 'standard__webPage',
                        attributes: { url: this.url }
                    });
                }
            }
        }
    } else {
        if (this.printPage) {
            window.print();
        }
    }
}

// Good: Refactored with early returns and helper methods
handleClick() {
    if (this.url) {
        this.handleUrlClick();
    } else if (this.printPage) {
        window.print();
    }
    this.dispatchEvent(new CustomEvent('actionclicked'));
}

handleUrlClick() {
    if (this.copyUrl) {
        this.handleCopy();
        return;
    }
    if (this.newTab) {
        this.openInNewTab();
    } else {
        this.navigateToUrl();
    }
}

navigateToUrl() {
    const navigateConfig = REGEX_SALESFORCE.test(this.url)
        ? this.getRecordPageConfig()
        : this.getWebPageConfig();
    this[NavigationMixin.Navigate](navigateConfig);
}

Method Length Guidelines

Guidelines:

  • Keep methods under 50 lines when possible
  • Refactor long methods into smaller, focused methods
  • Each method should do one thing well

Code Complexity Best Practices

  • Keep methods simple and focused
  • Prefer guard clauses and early returns; multiple exits are fine when the flow stays clear (see Return statement patterns)
  • Refactor complex logic into helper methods
  • Avoid deep nesting
  • Use descriptive method names

Performance Optimization

Lazy Loading

Usage: Use lazy loading for heavy components or data that's not immediately needed.

Guidelines:

  • Load data on demand when possible
  • Use lwc:if to conditionally render heavy components
  • Load third-party libraries only when needed

Examples:

// Good: Lazy load data
async loadData() {
    if (!this.dataLoaded) {
        this.isLoading = true;
        this.data = await fetchData();
        this.dataLoaded = true;
        this.isLoading = false;
    }
}

// Good: Conditionally render heavy component
get shouldRenderChart() {
    return this.data && this.data.length > 0;
}
<!-- Good: Single element - lwc:if on the element itself -->
<c-chart-component lwc:if={shouldRenderChart} data={data}></c-chart-component>

Wire Adapter Optimization

Usage: Optimize wire adapter usage for performance.

Guidelines:

  • Use cacheable=true for Apex methods when possible
  • Use reactive parameters efficiently
  • Avoid unnecessary wire adapter calls
  • Handle wire adapter errors appropriately

Examples:

// Good: Use cacheable for read-only data
@wire(getAccountData, { accountId: '$recordId' })
wiredAccountData({ error, data }) {
    // Handle data/error
}

// Apex method with cacheable
@AuraEnabled(cacheable=true)
public static Account getAccountData(Id accountId) {
    return [SELECT Id, Name FROM Account WHERE Id = :accountId];
}

Rendering Optimization

Usage: Optimize component rendering for performance.

Guidelines:

  • Use lwc:if to conditionally render elements
  • Avoid unnecessary re-renders
  • Use lwc:key with lwc:for for efficient list rendering
  • Minimize DOM manipulation in renderedCallback

Examples:

<!-- Good: Single element - lwc:if on the element itself -->
<p lwc:if={isVisible}>Content</p>

<!-- Good: Multiple elements - wrap in template -->
<template lwc:if={isVisible}>
    <p>Content</p>
    <p>Additional content</p>
</template>

<!-- Good: Use lwc:key for efficient list rendering -->
<ul>
    <template lwc:for={items} lwc:key={item.id}>
        <li>{item.name}</li>
    </template>
</ul>

Performance Best Practices

  • Use lazy loading for heavy components/data
  • Optimize wire adapter usage
  • Minimize DOM manipulation
  • Use conditional rendering appropriately
  • Use lwc:key with lists
  • Avoid unnecessary re-renders
  • Cache expensive computations

Component Composition

Parent-Child Communication

Usage: Use events for parent-child communication.

Child Component:

// Child dispatches event
handleClick() {
    this.dispatchEvent(new CustomEvent('itemclicked', {
        detail: {
            itemId: this.itemId,
            itemData: this.itemData
        },
        bubbles: true,
        composed: true
    }));
}

Parent Component:

<!-- Parent listens to event -->
<c-child-component onitemclicked={handleItemClicked}></c-child-component>
// Parent handles event
handleItemClicked(event) {
    const { itemId, itemData } = event.detail;
    // Handle event
}

Public API Pattern

Usage: Expose public methods for parent components to control child behavior.

Examples:

// Child component exposes public methods
@api focus() {
    const input = this.template.querySelector('input');
    if (input) {
        input.focus();
    }
}

@api reset() {
    this.value = '';
    this.error = undefined;
}

// Parent component calls public methods
handleFocusChild() {
    const child = this.template.querySelector('c-child-component');
    if (child) {
        child.focus();
    }
}

Component Interaction Patterns

Guidelines:

  • Use events for child-to-parent communication
  • Use public methods for parent-to-child control
  • Use message channels for cross-component communication
  • Keep component interfaces clear and documented

Composition Best Practices

  • Use events for upward communication
  • Use public methods for downward control
  • Use message channels for sibling communication
  • Keep components loosely coupled
  • Document component interfaces
  • Use clear, descriptive event names

Security

XSS Prevention

Usage: Prevent Cross-Site Scripting (XSS) attacks by properly handling user input.

Guidelines:

  • Never use innerHTML with user input
  • Use LWC's built-in data binding (safe by default)
  • Sanitize user input if needed
  • Use lightning-formatted-* components for safe rendering

Examples:

<!-- Good: Safe data binding -->
<p>{userInput}</p>

<!-- Good: Use lightning-formatted components -->
<lightning-formatted-rich-text value={richText}></lightning-formatted-rich-text>
// Bad: Unsafe innerHTML manipulation
renderedCallback() {
    const div = this.template.querySelector('.content');
    div.innerHTML = this.userInput; // UNSAFE!
}

// Good: Use safe data binding
// Template: <div>{userInput}</div>

Input Validation

Usage: Validate all user input before processing.

Guidelines:

  • Validate input on both client and server side
  • Provide clear error messages for invalid input
  • Sanitize input when necessary
  • Use type checking and validation utilities

Examples:

// Good: Validate input
handleInputChange(event) {
    const value = event.target.value;
    if (!this.isValidInput(value)) {
        this.error = 'Invalid input';
        return;
    }
    this.value = value;
    this.error = undefined;
}

isValidInput(value) {
    // Validation logic
    return value && value.length > 0 && value.length <= 255;
}

Secure Data Handling

Guidelines:

  • Don't expose sensitive data in component properties
  • Use secure methods for data transmission
  • Handle errors without exposing sensitive information
  • Follow Salesforce security best practices

Security Best Practices

  • Prevent XSS attacks
  • Validate all user input
  • Handle data securely
  • Don't expose sensitive information
  • Use LWC's safe data binding
  • Follow Salesforce security guidelines

Browser Compatibility

Supported Browsers

Salesforce LWC supports:

  • Chrome (latest 2 versions)
  • Firefox (latest 2 versions)
  • Safari (latest 2 versions)
  • Edge (latest 2 versions)

Guidelines:

  • Test components in supported browsers
  • Use feature detection when needed
  • Avoid browser-specific code when possible
  • Use polyfills for unsupported features if necessary

Compatibility Considerations

Guidelines:

  • Use standard JavaScript features
  • Avoid experimental features
  • Test in all supported browsers
  • Use feature detection for optional features

Examples:

// Good: Feature detection
if (navigator.clipboard && navigator.clipboard.writeText) {
    navigator.clipboard.writeText(this.url);
} else {
    // Fallback for older browsers
    this.fallbackCopyToClipboard(this.url);
}

API Version Standards

API Version Selection

Usage: Use the latest API version from the project (currently 65.0).

Guidelines:

  • Keep API versions consistent across components
  • Update API versions as part of regular maintenance
  • Don't manually set API version unless necessary
  • Document any exceptions to standard API version

API Version Maintenance

Guidelines:

  • Review API versions periodically
  • Update to latest API version during maintenance windows
  • Test components after API version updates
  • Document API version changes

API Version Best Practices

  • Use consistent API versions
  • Update API versions regularly
  • Test after API version updates
  • Document API version exceptions

Code Maintenance

TODO/FIXME Comments

Usage: TODO and FIXME comments are acceptable if there is a discussion, issue, or bug created to capture that work.

Format:

// TODO: [Issue #123] Migrate to lwc:if directive
// FIXME: [Bug #456] Handle edge case when recordId is null

Bad Example:

// TODO: Fix this later
// FIXME: This doesn't work

Conditional Rendering Migration

Requirement: Any existing if:true/if:false should be migrated to lwc:if when touching the component.

Migration Guidelines:

  • Single element: Place lwc:if directly on the element (no template wrapper needed)
  • Multiple elements: Wrap in <template> tag with lwc:if
  • No logic in brackets: Convert expressions to getters

Examples:

<!-- Old syntax (should be migrated) -->
<p if:true={isVisible}>Content</p>
<lightning-button if:true={showButton} label="Click Me"></lightning-button>

<!-- New syntax (preferred) - single element -->
<p lwc:if={isVisible}>Content</p>
<lightning-button lwc:if={showButton} label="Click Me"></lightning-button>

<!-- New syntax (preferred) - multiple elements -->
<template lwc:if={isVisible}>
    <p>Content</p>
    <p>Additional content</p>
</template>

<!-- Old syntax with logic (should be migrated) -->
<p if:true={status === 'success'} role="status">Success</p>

<!-- New syntax - use getter instead of logic in brackets -->
<!-- JavaScript: get isSuccess() { return this.status === 'success'; } -->
<p lwc:if={isSuccess} role="status">Success</p>

Deprecation Process

Note: This topic requires further discussion and planning. The deprecation process should include:

  1. Documentation - Document why the code is deprecated and what to use instead
  2. Transition Period - Provide a grace period for migration
  3. Process to List Usages/Updates - Track all usages and required updates

Placeholder for Future Implementation:

/**
 * @description [DEPRECATED] Use lwc:if directive instead
 * @deprecated This property will be removed in version 2.0. Use lwc:if in template instead.
 * @see Component documentation for migration guide
 */
@api get isVisible() {
    return this._isVisible;
}

Code Maintenance Best Practices

  • Address TODOs when touching components
  • Migrate if:true/if:false to lwc:if when updating components
  • Keep code up to date with latest LWC features
  • Remove unused code
  • Update documentation with code changes
  • Follow deprecation process when removing features

Change History

Version 1.0 - 2026-03-26

  • Added initial version history tracking for this document.

Last Updated: 2026-03-26 Version: 1.0