In this post, I am focusing on the custom lookup component missing as a seeded control in lightning.

Prerequisites: Basic knowledge of lightning component, Javascript .
Implementation
This implementation requires the following members. The server-side interaction of the component is not included in this implementation, you can develop it yourself, based on the requirement. Comment below if you need any help on that.
- SimpleLookup.cmp
- SimpleLookupController.js
- SimpleLookupHelper.js
- SimpleLookup.css
SimpleLookup.cmp
<aura:component > | |
<aura:attribute name="label" type="String" access="global" default="Search"/> | |
<aura:attribute name="selectedRecord" type="sObject" default="{name:'Account1'}" /> | |
<aura:attribute name="fetchedRecords" type="List" /> | |
<aura:attribute name="searchText" type="String"/> | |
<div aura:id="lookUpPane" class="slds-form-element slds-lookup slds-is-close" onmouseleave="{!c.onLeaveLookupPane}"> | |
<label class="slds-form-element__label" for="lookup-text">{!v.label}</label> | |
<div class="slds-form-element__control"> | |
<div aura:id="master-container" class="slds-combobox_container slds-has-object-switcher"> | |
<div class="slds-input-has-icon slds-input-has-icon–right input-container"> | |
<!– This part displays the slds pill –> | |
<div aura:id="selected-item-pill" class="slds-hide pill-container"> | |
<lightning:pill class="pill-item-size" label="{!v.selectedRecord.name}" name="{!v.selectedRecord.name}" onremove="{! c.remove }"> | |
</lightning:pill> | |
</div> | |
<!– This part displays the input control for search–> | |
<div aura:id="input-area" class="slds-show"> | |
<lightning:icon class="slds-input__icon slds-show" iconName="utility:search " size="x-small" alternativeText="search"/> | |
<ui:inputText aura:id="searchContent" class="slds-lookup__search-input slds-input input-no-border" value="{!v.searchText}" updateOn="keyup" keyup="{!c.onInputChange}" click="{!c.onSearchInputClick}"/> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!– | |
Lookup container to list down the records matched with the criteria | |
–> | |
<div id="listbox-unique-id" class="lookup-container" role="listbox"> | |
<ul class="slds-listbox slds-listbox_vertical slds-dropdown slds-dropdown_fluid slds-lookup__menu" role="presentation"> | |
<aura:iteration var="record" items="{!v.fetchedRecords}" indexVar="index"> | |
<li role="presentation" class="slds-listbox__item" onclick="{!c.selectedRecordRowClick}" data-index="{!index}"> | |
<div id="listbox-option-unique-id-01" class="slds-media slds-listbox__option slds-listbox__option_entity slds-listbox__option_has-meta" role="option"> | |
<!–<span class="slds-media__figure"> | |
<span class="slds-icon_container slds-icon-standard-account" title="Description of icon when needed"> | |
<span class="slds-assistive-text">Description of icon when needed</span> | |
</span> | |
</span>–> | |
<span class="slds-media__body"> | |
<span class="slds-listbox__option-text slds-listbox__option-text_entity">{!record.name}</span> | |
<span class="slds-listbox__option-meta slds-listbox__option-meta_entity">{!record.description}</span> | |
</span> | |
</div> | |
</li> | |
</aura:iteration> | |
</ul> | |
</div> | |
</div> | |
</aura:component> |
In the above component view part, I have declared four aura attributes
- label – display label of the component
- fetchedRecords – list of records matched with filter criteria
- searchText –Â content of input textbox, used as filter criteria for record processing
- selectedRecord – holds the current user selection
The Custom Lookup view splits into three sections
- Input Container –Â for inserting search criteria
- Lookup list with a container – list the matched items based on the input
- SLDS-pill – to show the selected list item
Please see the code comments for more details.
SimpleLookupController.js
({ | |
onLeaveLookupPane : function(component, event, helper) { | |
//Search – Input control focus removed on mouse leave | |
var inputContainerCmp = component.find('master-container'); | |
helper.removeClass(inputContainerCmp,'slds-has-input-focus'); | |
}, | |
remove : function (component, event, helper) { | |
//Hide the active SLDS – pill | |
var selectedItemPill = component.find('selected-item-pill'); | |
helper.hideElement(selectedItemPill); | |
//Show search-input control | |
var inputElement = component.find('input-area'); | |
helper.showElement(inputElement); | |
}, | |
onInputChange : function (component, event, helper) { | |
var searchContent = component.get("v.searchText"); | |
var lookupContainerCmp = component.find("lookUpPane"); | |
if ( searchContent && searchContent.trim().length > 0 ) { | |
searchContent = searchContent.trim(); | |
helper.addClass(lookupContainerCmp,'slds-is-open'); | |
helper.removeClass(lookupContainerCmp,'slds-is-close'); | |
helper.searchContent(component,searchContent); | |
} else { | |
helper.removeClass(lookupContainerCmp,'slds-is-open'); | |
helper.addClass(lookupContainerCmp,'slds-is-close'); | |
} | |
}, | |
onSearchInputClick : function (component, event, helper) { | |
//input control foucs enabled by adding focus style class | |
var inputContainerCmp = component.find('master-container'); | |
helper.addClass(inputContainerCmp,'slds-has-input-focus'); | |
}, | |
selectedRecordRowClick : function (component, event, helper) { | |
//event triggered on lookup row selection | |
//fetching the details of selected row and it's index | |
var targetSource = event.currentTarget; | |
var selectedIndex = targetSource.dataset.index; | |
console.log(targetSource,selectedIndex); | |
var listedRecords = component.get("v.fetchedRecords"); | |
if (listedRecords && listedRecords.length > 0 && +selectedIndex >=0) { | |
var selectedRecord = listedRecords[selectedIndex]; | |
//Search input control value resets | |
component.find("searchContent").set("v.value",""); | |
//Hide the lookup | |
var lookupContainerCmp = component.find("lookUpPane"); | |
helper.removeClass(lookupContainerCmp,'slds-is-open'); | |
helper.addClass(lookupContainerCmp,'slds-is-close'); | |
//Show Selected row content as a SLDS – pill | |
var selectedItemPill = component.find('selected-item-pill'); | |
helper.showElement(selectedItemPill); | |
//Hide the search-input control | |
var inputElement = component.find('input-area'); | |
helper.hideElement(inputElement); | |
} | |
} | |
}) |
The JS methods mainly focused on the visibility (show or hide) of the view elements rather than doing complex logic.
- onLeaveLookupPane – to hide the lookup container
- remove – to hide the slds-pill and show the input text field
- onInputChange – triggers on the keyup event of the input text field and displays the lookup container with the filtered data as a list by invoking “searchContent“ helper method.
- onSearchInputClick – adds the standard SLDS input-focus style
- selectedRecordRowClick – triggers when a list item is selected from the lookup container and displayed the selected list item as an SLDS-pill after hiding the input container.
Please see the code comments for more details.
SimpleLookupHelper.js
({ | |
addClass : function (element, className) { | |
//Global Aura util method for adding a style class from an aura element | |
$A.util.addClass(element,className); | |
}, | |
removeClass : function (element , className) { | |
//Global Aura util method for removing a style class from an aura element | |
$A.util.removeClass(element,className); | |
}, | |
showElement : function (element) { | |
//To show an aura html element | |
var self = this; | |
self.removeClass(element,'slds-hide'); | |
self.addClass(element,'slds-show'); | |
}, | |
hideElement : function (element) { | |
//To hide an aura html element | |
var self = this; | |
self.removeClass(element,'slds-show'); | |
self.addClass(element,'slds-hide'); | |
}, | |
searchContent : function (component,searchContent) { | |
//The helper method calls sets the matched search content to component view | |
//Now, it is returing some dummy records | |
//Note – In your application – you should call the server method here with search query string | |
//(searchContent)as parameter. | |
//Matched records should sets to v.fetchedRecords attribute. | |
var record = [{"name": "Account1","description":"Account . Location1"}, | |
{"name": "Account2","description":"Account . Location2"}, | |
{"name": "Account3","description":"Account . Location3"}, | |
{"name": "Account4","description":"Account . Location4"}, | |
{"name": "Account5","description":"Account . Location5"}, | |
{"name": "Account6","description":"Account . Location6"}, | |
{"name": "Account7","description":"Account . Location7"} | |
]; | |
component.set("v.fetchedRecords",record); | |
} | |
}) |
The searchContent method is used for assigning sample records to fetchedRecords aura attribute. You can replace the existing sample code with functional one which can fetch the records from the apex controller on the server side.
- add/removeClass – overridden method for adding or removing style class.
- Show/HideElement – show or hide the HTML element based on the input
Please see the code comments for more details.
SimpleLookup.css
.THIS .pill-item-size,.THIS .input-container { | |
width : 100% | |
} | |
.THIS .pill-container{ | |
font-size: medium; | |
margin: .5px; | |
} | |
.THIS .input-no-border{ | |
border : transparent; | |
} | |
.THIS .input-no-border:focus{ | |
outline: transparent; | |
border-color: inherit; | |
-webkit-box-shadow: none; | |
box-shadow: none; | |
} |

Don’t forget to share the post if you like it & bookmark the blog for future references.
If you have any comments or doubts on this post, Please comment on the box below.
This doesn’t seem to work with record edit.
What are the code changes needed for the same ?
Moreover, how can I support lookup filter feature in this markup ?
I couldn’t understand your point , it will work on the record edit since it is a custom component right?
To incorporate the filters you need to add view attributes and pass it to the apex controller