Hello Everyone, In this tutorial, I am going provide a Lightning Component example that contains inline editing functionality on the Salesforce record. Inline editing lets users quickly edit the field value right on a record's detail pages. So without wasting the time let's get started, 

Inline Editing in Lightning Component

For this functionality, I have created two lightning component and an apex class.

Step 1: Login to your Salesforce Org. and open developer console.



Step 2: Go to File>New>Apex Class and Create an Apex controller called InlineEditHandlerReplace following code in apex controller.  

InlineEditHandler.apxc
 public class InlineEditHandler {
    
    @AuraEnabled
    public static List <Account> getAccount() {
        List <Account> lstOfAccount = [SELECT id, Name, Rating, website FROM Account LIMIT 5];
        return lstOfAccount;
    }
    
    @AuraEnabled
    public static List <Account> saveAccount(List<Account> lstAccount) {
        update lstAccount;
        return lstAccount;
    }
    
    @AuraEnabled
    public static List < String > getselectOptions(sObject objObject, string fld) {       
        List < String > allOpts = new list < String > ();
        Schema.sObjectType objType = objObject.getSObjectType();
        Schema.DescribeSObjectResult objDescribe = objType.getDescribe();
        MAP < String, Schema.SObjectField > fieldMap = objDescribe.fields.getMap();
        List < Schema.PicklistEntry > values = fieldMap.get(fld).getDescribe().getPickListValues();
        for (Schema.PicklistEntry a: values) {
            allOpts.add(a.getValue());
        }
        allOpts.sort();
        return allOpts;
    }    
 }
Step 3: Go to File>New>Lightning Component and create a Lightning Component called InlineEditChild. Replace the following markup in the Lightning Component.

InlineEditChild.cmp
 <aura:component controller="InlineEditHandler">     
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>    
    <aura:attribute name="objInfoForPicklistValues" type="account" default="{sobjectType : 'Account'}" description="object information to fetch picklist values"/>
    <aura:attribute name="ratingPicklistOpts" type="string[]" description="store picklist options values"/>
    <aura:attribute name="showSaveCancelBtn" type="boolean"/>
    <aura:attribute name="showErrorClass" type="boolean" default="false"/>
    <aura:attribute name="sNo" type="string" />
    <aura:attribute name="nameEditMode" type="boolean" default="false" />
    <aura:attribute name="WebsiteEditMode" type="boolean" default="false" />
    <aura:attribute name="ratingEditMode" type="boolean" default="false" />
    <aura:attribute name="singleRec" type="sobject" default="{'sobjectType' : 'account',
                                                             'Name' : '','Website' : '',
                                                             'AnnualRevenue' :'','Rating': ''
                                                             }"/>
    <tr>
        <td><div class="slds-truncate">{!v.sNo}</div></td>
        <td ondblclick="{!c.inlineEditName}" class="{! v.showErrorClass == true ? 'slds-cell-edit slds-has-error' : 'slds-cell-edit'}">
            <span class="slds-grid slds-grid_align-spread">
                <!-- show input and output section based on boolean flag -->
                <aura:if isTrue="{!v.nameEditMode == false}">
                    <span class="slds-truncate" title="Name">{!v.singleRec.Name}</span>
                    <button onclick="{!c.inlineEditName}" class="slds-button slds-button_icon slds-cell-edit__button slds-m-left_x-small" tabindex="0" title="Edit Name">
                        <lightning:icon iconName="utility:edit" size="xx-small" alternativeText="edit"/>
                    </button>
                    <!-- Inline Edit Section in else case-->
                    <aura:set attribute="else">
                        <section  tabindex="0" class="slds-popover slds-popover_edit" role="dialog" style="position: absolute; top: 0px">
                            <div class="slds-popover__body">
                                <div class="slds-form-element slds-grid slds-wrap">
                                    <div class="slds-form-element__control slds-grow">
                                        <ui:inputText class="slds-input inputWidth"
                                                      labelClass="slds-form-element__label slds-form-element__label_edit slds-no-flex"
                                                      aura:id="inputId"
                                                      blur="{!c.closeNameBox}"
                                                      change="{!c.onNameChange}"
                                                      required="true"
                                                      label="Name"
                                                      value="{!v.singleRec.Name}" />
                                    </div>
                                </div>
                            </div>
                            <span id="form-end" tabindex="0"></span>
                        </section>
                    </aura:set>
                </aura:if>
            </span>
        </td>
        <td ondblclick="{!c.inlineEditWebsite}">
            <span class="slds-grid slds-grid_align-spread">
                <!-- show input and output section based on boolean flag -->
                <aura:if isTrue="{!v.WebsiteEditMode == false}">
                    <span class="slds-truncate" title="Website">{!v.singleRec.Website}</span>
                    <button onclick="{!c.inlineEditWebsite}" class="slds-button slds-button_icon slds-cell-edit__button slds-m-left_x-small" tabindex="0" title="Edit Website">
                        <lightning:icon iconName="utility:edit" size="xx-small" alternativeText="edit"/>
                    </button>
                    <!-- Inline Edit Section in else case-->
                    <aura:set attribute="else">
                        <section  tabindex="0" class="slds-popover slds-popover_edit" role="dialog" style="position: absolute; top: 0px">
                            <div class="slds-popover__body">
                                <div class="slds-form-element slds-grid slds-wrap">
                                    <div class="slds-form-element__control slds-grow">
                                        <ui:inputText class="slds-input inputWidth"
                                                      labelClass="slds-form-element__label slds-form-element__label_edit slds-no-flex"
                                                      aura:id="inputWebsiteId"
                                                      blur="{!c.closeWebsiteBox}"
                                                      change="{!c.onWebsiteChange}"                                                      
                                                      label="Website"
                                                      value="{!v.singleRec.Website}" />
                                    </div>
                                </div>
                            </div>
                            <span id="form-end" tabindex="0"></span>
                        </section>
                    </aura:set>
                </aura:if>
            </span>
        </td>
        <td ondblclick="{!c.inlineEditRating}">
            <span class="slds-grid slds-grid_align-spread">
                <!-- show input and output section based on boolean flag -->
                <aura:if isTrue="{!v.ratingEditMode == false}">
                    <span class="slds-truncate" title="Rating">{!v.singleRec.Rating}</span>
                    <button onclick="{!c.inlineEditRating}" class="slds-button slds-button_icon slds-cell-edit__button slds-m-left_x-small" tabindex="0" title="Edit Rating">
                        <lightning:icon iconName="utility:edit" size="xx-small" alternativeText="edit"/>
                    </button>
                    <!-- Inline Edit Section in else case-->
                    <aura:set attribute="else">
                        <section  tabindex="0" class="slds-popover slds-popover_edit" role="dialog" style="position: absolute; top: 0px;width:80%">
                            <div class="slds-popover__body">
                                <div class="slds-form-element slds-grid slds-wrap">
                                    <div class="slds-form-element__control slds-grow">
                                        <label class="slds-form-element__label">Rating</label>
                                        <ui:inputSelect aura:id="accRating"
                                                        class="slds-select inputRatingWidth"
                                                        blur="{!c.closeRatingBox}"
                                                        change="{!c.onRatingChange}"
                                                        value="{!v.singleRec.Rating}"
                                                        />
                                    </div>
                                </div>
                            </div>
                            <span id="form-end" tabindex="0"></span>
                        </section>
                    </aura:set>
                </aura:if>
            </span>
        </td>
    </tr>    
 </aura:component> 
InlineEditChildController.js 
 ({    
    doInit: function(component, event, helper) {
        helper.fetchPickListVal(component, 'Rating', 'ratingPicklistOpts');
    },
    
    inlineEditName : function(component,event,helper){  
        component.set("v.nameEditMode", true);
        setTimeout(function(){
            component.find("inputId").focus();
        }, 100);
    },
    
    inlineEditWebsite : function(component,event,helper){  
        component.set("v.WebsiteEditMode", true);
        setTimeout(function(){
            component.find("inputWebsiteId").focus();
        }, 100);
    },
    
    inlineEditRating : function(component,event,helper){  
        component.set("v.ratingEditMode", true);
        component.find("accRating").set("v.options" , component.get("v.ratingPicklistOpts"));
        setTimeout(function(){
            component.find("accRating").focus();
        }, 100);
    },
    
    onNameChange : function(component,event,helper){
        if(event.getSource().get("v.value").trim() != ''){
            component.set("v.showSaveCancelBtn",true);
        }
    },
    
    onWebsiteChange : function(component,event,helper){
        if(event.getSource().get("v.value").trim() != ''){
            component.set("v.showSaveCancelBtn",true);
        }
    },
    
    onRatingChange : function(component,event,helper){
        component.set("v.showSaveCancelBtn",true);
    },    
    
    closeNameBox : function (component, event, helper) {
        component.set("v.nameEditMode", false);
        if(event.getSource().get("v.value").trim() == ''){
            component.set("v.showErrorClass",true);
        }
        else{
            component.set("v.showErrorClass",false);
        }
    },
    
    closeWebsiteBox : function (component, event, helper) {       
        component.set("v.WebsiteEditMode", false);        
    },
    
    closeRatingBox : function (component, event, helper) {
        component.set("v.ratingEditMode", false);
    },     
 })
InlineEditChildHelper.js
 ({
    fetchPickListVal: function(component, fieldName, picklistOptsAttributeName) {
        var action = component.get("c.getselectOptions");
        action.setParams({
            "objObject": component.get("v.objInfoForPicklistValues"),
            "fld": fieldName
        });
        var opts = [];
        action.setCallback(this, function(response) {
            if (response.getState() == "SUCCESS") {
                var allValues = response.getReturnValue();                
                if (allValues != undefined && allValues.length > 0) {
                    opts.push({
                        class: "optionClass",
                        label: "--- None ---",
                        value: ""
                    });
                }
                for (var i = 0; i < allValues.length; i++) {
                    opts.push({
                        class: "optionClass",
                        label: allValues[i],
                        value: allValues[i]
                    });
                }
                component.set("v." + picklistOptsAttributeName, opts);
            }
        });
        $A.enqueueAction(action);
    },    
 })
InlineEditChildStyle.css
 .THIS .inputWidth {
    width:80%;
 }

 .THIS .inputRatingWidth {
    width:75%;
 }
Step 4: Go to File>New>Lightning Component and create a Lightning Component called InlineEdit. Replace the following markup in the Lightning Component.

InlineEdit.cmp
 <aura:component controller="InlineEditHandler" implements="flexipage:availableForAllPageTypes,force:hasRecordId,force:appHostable">   
    <aura:handler name="init" value="{!this}" action="{!c.initRecords}"/>
    <aura:attribute name="AccountList" type="account[]" description="store account records list"/>
    <aura:attribute name="showSaveCancelBtn" type="boolean" default="false" description="flag for rendered save and cancel buttons in aura:if "/>    
    <br/><center style="font-size:16px;font-weight:bold;"><u>Edit Account Records</u></center><br/>      
    <table class="slds-table slds-table_bordered slds-table_cell-buffer">
        <thead>
            <tr class="slds-text-title--caps">
                <th scope="col"><div class="slds-truncate" title="Id">S.No</div></th>
                <th scope="col"><div class="slds-truncate" title="Account Name">Account Name</div></th>
                <th scope="col"><div class="slds-truncate" title="Website">Website</div></th>
                <th scope="col"><div class="slds-truncate" title="Rating">Rating</div></th>
            </tr>
        </thead>          
        <tbody>
            <!--### display all records of AccountList attribute one by one by aura:iteration ###-->
            <aura:iteration items="{!v.AccountList}" var="acc" indexVar="sNo">
                <!-- Child Lightning Component -->
                <c:InlineEditChild singleRec="{!acc}" showSaveCancelBtn="{!v.showSaveCancelBtn}" sNo="{!sNo + 1}" />
            </aura:iteration>
        </tbody>
    </table>
    <br/>
    <center>
        <!-- use aura:if for show/hide buttons -->      
        <aura:if isTrue="{!v.showSaveCancelBtn}">
            <!--button for save and cancel Record after Inline Edit-->
            <lightning:button label="Cancel" onclick="{!c.cancel}"/>&nbsp;
            <lightning:button label="Save" onclick="{!c.Save}" variant="success"/>                
        </aura:if> 
    </center>    
 </aura:component>
InlineEditController.js 
 ({
    initRecords: function(component, event, helper) {
        var action = component.get("c.getAccount");
        action.setCallback(this, function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                var storeResponse = response.getReturnValue();                
                component.set("v.AccountList", storeResponse);
            }
        });
        $A.enqueueAction(action);
    },
    
    Save: function(component, event, helper) {
        if (helper.requiredValidation(component, event)){
            var action = component.get("c.saveAccount");
            action.setParams({
                'lstAccount': component.get("v.AccountList")
            });
            action.setCallback(this, function(response) {
                var state = response.getState();
                if (state === "SUCCESS") {
                    var storeResponse = response.getReturnValue();
                    component.set("v.AccountList", storeResponse);
                    component.set("v.showSaveCancelBtn",false);
                    alert('Record Updated');
                }
            });
            $A.enqueueAction(action);
        }
    },
    
    cancel : function(component,event,helper){
        $A.get('e.force:refreshView').fire();
    }
 })
InlineEditHelper.js
 ({
    requiredValidation : function(component,event) {
        var allRecords = component.get("v.AccountList");
        var isValid = true;
        for(var i = 0; i < allRecords.length;i++){
            if(allRecords[i].Name == null || allRecords[i].Name.trim() == ''){
                alert('Complete this field : Row No ' + (i+1) + ' Name is null' );
                isValid = false;
            }
        }
        return isValid;
    }
 }) 
To see the output of this Lightning component create a Lightning Component tab (Setup | Create | Tabs | Lightning Component Tabs), then switch your Salesforce org in Lightning experience and click on the tab that you created earlier for this component.

Output:

See also:

Conclusion:
Hope you like this tutorial, for any query or suggestions please feel free to comment.
Thank you.