Skip to main content

Custom Field Validation in LWC: lightning-record-edit-form Best Practices

In plain words: The <lightning-record-edit-form> component in Lightning Web Components (LWC) provides built-in form handling, schema awareness, and database commits without custom Apex. By intercepting the form's onsubmit event in JavaScript, you can execute custom client-side validation rules, format input values, and stop invalid records from submitting before making a server roundtrip.

Standard Salesforce page layouts automatically enforce required fields and validation rules, but custom business processes often demand dynamic client-side checks—such as cross-field dependency validation, regex pattern checks, or conditional data requirements. Building custom edit forms with <lightning-record-edit-form> and <lightning-input-field> allows developers to create tailored multi-column layouts while retaining full control over data submission and error handling.

1. Understanding the Form Submission Lifecycle

Managing record edits with <lightning-record-edit-form> follows a structured event lifecycle:

  • onload: Fires when record data and schema metadata are fetched from Lightning Data Service (LDS).
  • onsubmit: Intercepted before data is sent to the server. Calling event.preventDefault() pauses submission so your JavaScript controller can inspect event.detail.fields and run custom validation logic.
  • onsuccess: Fires after the record successfully saves, providing the record ID in event.detail.id.
  • onerror: Captures server-side validation rule errors, trigger exceptions, and duplicate rule alerts.
360 Form Validation Architecture Card:
  • Core Component: <lightning-record-edit-form> & <lightning-input-field>
  • Event Hook: onsubmit={handleSubmit} with event.preventDefault().
  • Error Feedback: <lightning-messages> for standard banners or ShowToastEvent for popups.
  • Data Submission: this.template.querySelector('lightning-record-edit-form').submit(fields);
  • Security Advantage: Automatically respects Object and Field-Level Security (FLS) without custom Apex code.

2. Step-by-Step Implementation: Building the Validated Form

The following example creates a validated Account form that ensures custom conditional criteria are met before saving.

Step 1: HTML Template (accountRecordForm.html)
Structure the form using the Salesforce Lightning Design System (SLDS) grid system.
<template>
    <lightning-card title="Create Enterprise Account" icon-name="standard:account">
        <div class="slds-p-around_medium">
            <lightning-record-edit-form
                object-api-name="Account"
                onsubmit={handleSubmit}
                onsuccess={handleSuccess}
                onerror={handleError}>
                
                <!-- Displays standard platform error messages -->
                <lightning-messages></lightning-messages>

                <div class="slds-grid slds-wrap slds-gutters">
                    <div class="slds-col slds-size_1-of-1 slds-medium-size_1-of-2">
                        <lightning-input-field field-name="Name" required></lightning-input-field>
                    </div>
                    <div class="slds-col slds-size_1-of-1 slds-medium-size_1-of-2">
                        <lightning-input-field field-name="Industry" required></lightning-input-field>
                    </div>
                    <div class="slds-col slds-size_1-of-1 slds-medium-size_1-of-2">
                        <lightning-input-field field-name="AnnualRevenue"></lightning-input-field>
                    </div>
                    <div class="slds-col slds-size_1-of-1 slds-medium-size_1-of-2">
                        <lightning-input-field field-name="Phone"></lightning-input-field>
                    </div>
                </div>

                <div class="slds-m-top_medium">
                    <lightning-button
                        type="submit"
                        label="Save Account"
                        variant="brand"
                        class="slds-m-right_small">
                    </lightning-button>
                    <lightning-button
                        label="Cancel"
                        variant="neutral"
                        onclick={handleReset}>
                    </lightning-button>
                </div>
            </lightning-record-edit-form>
        </div>
    </lightning-card>
</template>
Step 2: JavaScript Controller (accountRecordForm.js)
Intercept the submission, execute custom validations, and dispatch toast notifications.
import { LightningElement, api } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { NavigationMixin } from 'lightning/navigation';

export default class AccountRecordForm extends NavigationMixin(LightningElement) {
    @api recordId;

    handleSubmit(event) {
        // Stop the form from submitting automatically
        event.preventDefault();
        
        const fields = event.detail.fields;

        // Custom Validation Rule 1: Required Name & Industry
        if (!fields.Name || !fields.Industry) {
            this.showToast('Validation Error', 'Account Name and Industry are required.', 'error', 'dismissable');
            return;
        }

        // Custom Validation Rule 2: Banking accounts must specify Annual Revenue
        if (fields.Industry === 'Banking' && (!fields.AnnualRevenue || Number(fields.AnnualRevenue) <= 0)) {
            this.showToast(
                'Revenue Required',
                'Annual Revenue must be greater than 0 for Banking accounts.',
                'warning',
                'sticky'
            );
            return;
        }

        // Submit the validated payload back to Lightning Data Service
        this.template.querySelector('lightning-record-edit-form').submit(fields);
    }

    handleSuccess(event) {
        const createdRecordId = event.detail.id;
        
        this.showToast(
            'Success',
            `Account created successfully with ID: ${createdRecordId}`,
            'success',
            'dismissable'
        );

        // Optional: Navigate to the newly created record page
        this[NavigationMixin.Navigate]({
            type: 'standard__recordPage',
            attributes: {
                recordId: createdRecordId,
                actionName: 'view'
            }
        });
    }

    handleError(event) {
        this.showToast(
            'Error Creating Record',
            event.detail.detail || 'An unexpected error occurred.',
            'error',
            'sticky'
        );
    }

    handleReset() {
        const inputFields = this.template.querySelectorAll('lightning-input-field');
        if (inputFields) {
            inputFields.forEach(field => {
                field.reset();
            });
        }
    }

    showToast(title, message, variant, mode) {
        this.dispatchEvent(
            new ShowToastEvent({
                title: title,
                message: message,
                variant: variant,
                mode: mode || 'dismissable'
            })
        );
    }
}

3. Common Traps & Developer Best Practices

Form Submission Trap: Forgetting event.preventDefault()
If you omit event.preventDefault() in the handleSubmit method, the form will submit the payload to the server immediately before your custom JavaScript validations finish executing. Always call event.preventDefault() first, validate your conditions, and only call submit(fields) when all rules pass.
Core Rule: Intercept onsubmit with event.preventDefault(), validate field values client-side to prevent unnecessary server trips, and use standard Lightning Design System grid classes instead of hardcoding pixel widths.
  • Use Native SLDS Grid Utilities: Rely on standard classes like slds-grid, slds-wrap, and slds-p-around_medium rather than writing custom CSS margin/padding rules.
  • Include <lightning-messages>: Always place <lightning-messages> inside the form so server-side validation rules and trigger exceptions render automatically for the user.
  • Form Reset Pattern: To clear form fields, iterate over all <lightning-input-field> nodes using this.template.querySelectorAll() and invoke their native .reset() method.

Summary

Implementing record forms with custom validation in Lightning Web Components provides a seamless, responsive experience for Salesforce users. By combining <lightning-record-edit-form> with client-side event interception and toast notifications, developers can enforce complex business requirements cleanly while reducing unnecessary server roundtrips.