Create Multi Select Combobox / picklist in Lightning Salesforce
Multi Select Combobox lightning component is easy to create and works for both single select and multi select.
Lightning comes with many pre-built components that are easy to use but still many components are missing by date. One of them is the multi-select Combobox/picklist component. We will create this within a single component without using any child component or event. You can find the complete source code in this post.
Multi Select Combobox component Features:
- Single component
- Options attribute to pass List
- Option to switch between Single Select and Multi Select.
- Separate attributes for single and multi select to get selected values.
- search functionality to filter options
- Option to set the minimum character to start searching
- Ability to set the label of combobox
- combobox disable functionality
Demo GIF:
Single Select Combobox:
Multi Select Combobox:
Requirement:
[supsystic-tables id=10]
Step-1: Create the MultiSelectCombobox Component
For creating a new lightning component navigate to Developer Console > File > New > Lightning Component
Enter Name & Description and click Submit. Now component markup file will open y default. In the right sidebar, click on Controller, Helper, and Style to create those files too.

Now since all the files are created, we will write markup for our component. I have used standard (Salesforce Lightning Design System) SLDS here for styling.
Markup for MultiSelectCombobox.cmp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
<!-- Code by CafeForce || www.cafeforce.com || support@cafeforce.com || Mandatory Header --> <aura:component> <!-- Attributes that can be set while component calling--> <aura:attribute name="options" type="string" default="" required="true" /> <aura:attribute name="value" type="String" default="" description="Selected value in single Select" /> <aura:attribute name="values" type="List" default="" description="Selected value in Multi Select" /> <aura:attribute name="label" type="string" default="" description="Label will be displayed above input Box" /> <aura:attribute name="minChar" type="Integer" default="1" description="Minimum character to type for search" /> <aura:attribute name="disabled" type="Boolean" default="false" description="Disable the combobox" /> <aura:attribute name="multiSelect" type="Boolean" default="false" description="Switch between single and multiSelect" /> <!-- Internal Use Attributes --> <aura:handler name="init" value="{!this}" action="{!c.doInit}"/> <aura:attribute name="searchString" type="string" access="private" default="" description="String to search"/> <aura:attribute name="message" type="String" access="private" default="" /> <!-- Component Markup --> <div> <aura:if isTrue="{!!empty(v.label)}"> <label class="slds-form-element__label">{!v.label}</label> </aura:if> <div class="slds-combobox_container"> <div class="slds-combobox slds-dropdown-trigger slds-dropdown-trigger_click slds-is-open" aura:id="resultsDiv" aria-expanded="true" aria-haspopup="listbox" role="combobox"> <div class="slds-combobox__form-element slds-input-has-icon slds-input-has-icon_right" role="none"> <lightning:input disabled="{!v.disabled}" aura:id="inputLookup" class="inputBox" placeholder="Select an Option" onblur="{!c.blurEvent}" onclick="{!c.showOptions}" onkeyup="{!c.filterOptions}" value="{!v.searchString}" autoComplete="off" variant="label-hidden" id="combobox-id-1" /> <lightning:icon class="slds-input__icon" iconName="utility:down" size="x-small" alternativeText="search"/> </div> <!-- Dropdown List --> <div id="listbox-id-1" class="slds-dropdown slds-dropdown_length-5 slds-dropdown_fluid" style="{! 'max-height:' + (8 + (v.recordCount * 40)) + 'px' }"> <ul class="slds-listbox slds-listbox_vertical recordListBox" role="presentation"> <aura:if isTrue="{!empty(v.message)}" > <!-- To display Drop down List --> <aura:iteration items="{!v.options}" var="option" > <aura:if isTrue="{!option.disabled}"> <li class="{!'slds-listbox__item disabledItem' + if(option.isVisible,'',' slds-hide')}"> <span class="slds-media slds-listbox__option_entity verticalAlign slds-truncate">{!option.label}</span> </li> <aura:set attribute="else"> <li id="{!option.value}" class="{!'slds-listbox__item eachItem' + if(option.isVisible,'',' slds-hide')}" onmousedown="{!c.selectItem}"> <lightning:icon class="{!if(option.selected,'','slds-hide')}" iconName="utility:check" size="x-small" alternativeText="icon" /> <span class="slds-media slds-listbox__option_entity verticalAlign slds-truncate">{!option.label}</span> </li> </aura:set> </aura:if> </aura:iteration> <!-- To display Error Message --> <aura:set attribute="else"> <li class="slds-listbox__item"> <span class="slds-media slds-listbox__option_entity verticalAlign slds-truncate">{!v.message}</span> </li> </aura:set> </aura:if> </ul> </div> </div> </div> <aura:iteration items="{!v.options}" var="option"> <aura:if isTrue="{!option.selected}"> <lightning:pill class="slds-m-around_xx-small" name="{!option.value}" label="{!option.label}" onremove="{!c.removePill}"/> </aura:if> </aura:iteration> </div> </aura:component> <!-- Code by CafeForce Website: http://www.cafeforce.com DO NOT REMOVE THIS HEADER/FOOTER FOR FREE CODE USAGE --> |
Now open the controller file MultiSelectComboboxController.js and paste the below code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
({ // To prepopulate the seleted value pill if value attribute is filled doInit : function( component, event, helper ) { helper.doInitHelper(component); }, // When a keyword is entered in search box filterOptions : function( component, event, helper ) { if( !$A.util.isEmpty(component.get('v.searchString')) ) { helper.filterOptionsHelper(component); } else { $A.util.removeClass(component.find('resultsDiv'),'slds-is-open'); } }, // When an item is selected selectItem : function( component, event, helper ) { if(!$A.util.isEmpty(event.currentTarget.id)) { helper.selectItemHelper(component, event); } }, showOptions : function( component, event, helper ) { var disabled = component.get("v.disabled"); if(!disabled) { component.set("v.message", ''); component.set('v.searchString', ''); var options = component.get("v.options"); options.forEach( function(element,index) { element.isVisible = true; }); component.set("v.options", options); if(!$A.util.isEmpty(component.get('v.options'))) { $A.util.addClass(component.find('resultsDiv'),'slds-is-open'); } } }, // To remove the selected item. removePill : function( component, event, helper ){ helper.removePillHelper(component, event); }, // To close the dropdown if clicked outside the dropdown. blurEvent : function( component, event, helper ){ helper.blurEventHelper(component, event); }, }) /* Code by CafeForce Website: http://www.cafeforce.com DO NOT REMOVE THIS HEADER/FOOTER FOR FREE CODE USAGE */ |
Open the helper file MultiSelectComboboxHelper.js and paste the below code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
({ doInitHelper : function(component) { $A.util.toggleClass(component.find('resultsDiv'),'slds-is-open'); var value = component.get('v.value'); var values = component.get('v.values'); if( !$A.util.isEmpty(value) || !$A.util.isEmpty(values) ) { var searchString; var count = 0; var multiSelect = component.get('v.multiSelect'); var options = component.get('v.options'); options.forEach( function(element, index) { if(multiSelect) { if(values.includes(element.value)) { element.selected = true; count++; } } else { if(element.value == value) { searchString = element.label; } } }); if(multiSelect) component.set('v.searchString', count + ' options selected'); else component.set('v.searchString', searchString); component.set('v.options', options); } }, filterOptionsHelper : function(component) { component.set("v.message", ''); var searchText = component.get('v.searchString'); var options = component.get("v.options"); var minChar = component.get('v.minChar'); if(searchText.length >= minChar) { var flag = true; options.forEach( function(element,index) { if(element.label.toLowerCase().trim().startsWith(searchText.toLowerCase().trim())) { element.isVisible = true; flag = false; } else { element.isVisible = false; } }); component.set("v.options",options); if(flag) { component.set("v.message", "No results found for '" + searchText + "'"); } } $A.util.addClass(component.find('resultsDiv'),'slds-is-open'); }, selectItemHelper : function(component, event) { var options = component.get('v.options'); var multiSelect = component.get('v.multiSelect'); var searchString = component.get('v.searchString'); var values = component.get('v.values') || []; var value; var count = 0; options.forEach( function(element, index) { if(element.value === event.currentTarget.id) { if(multiSelect) { if(values.includes(element.value)) { values.splice(values.indexOf(element.value), 1); } else { values.push(element.value); } element.selected = element.selected ? false : true; } else { value = element.value; searchString = element.label; } } if(element.selected) { count++; } }); component.set('v.value', value); component.set('v.values', values); component.set('v.options', options); if(multiSelect) component.set('v.searchString', count + ' options selected'); else component.set('v.searchString', searchString); if(multiSelect) event.preventDefault(); else $A.util.removeClass(component.find('resultsDiv'),'slds-is-open'); }, removePillHelper : function(component, event) { var value = event.getSource().get('v.name'); var multiSelect = component.get('v.multiSelect'); var count = 0; var options = component.get("v.options"); var values = component.get('v.values') || []; options.forEach( function(element, index) { if(element.value === value) { element.selected = false; values.splice(values.indexOf(element.value), 1); } if(element.selected) { count++; } }); if(multiSelect) component.set('v.searchString', count + ' options selected'); component.set('v.values', values) component.set("v.options", options); }, blurEventHelper : function(component, event) { var selectedValue = component.get('v.value'); var multiSelect = component.get('v.multiSelect'); var previousLabel; var count = 0; var options = component.get("v.options"); options.forEach( function(element, index) { if(element.value === selectedValue) { previousLabel = element.label; } if(element.selected) { count++; } }); if(multiSelect) component.set('v.searchString', count + ' options selected'); else component.set('v.searchString', previousLabel); if(multiSelect) $A.util.removeClass(component.find('resultsDiv'),'slds-is-open'); } }) /* Code by CafeForce Website: http://www.cafeforce.com DO NOT REMOVE THIS HEADER/FOOTER FOR FREE CODE USAGE */ |
Finally paste the CSS in MultiSelectCombobox.css file.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
.THIS .verticalAlign { cursor: pointer; padding: 0px 5px !important; } .THIS .slds-dropdown { padding:0px !important; } .THIS .fullWidth { width: 100% !important; } .THIS .disabledItem { color: #bbb; cursor: no-drop; } .THIS .recordListBox { margin-top:0px !important; overflow-y: scroll; } .THIS .slds-listbox li { padding: .45rem 0.7rem !important; display: flex; } .THIS .inputBox input { padding-left: 10px; } .THIS .eachItem:hover { background-color: #F1F1F1; cursor: pointer; } .THIS .inputIcon { z-index: 99; padding: 2px 0; } /* For Scrolling */ .THIS ::-webkit-scrollbar { width: 7px; height: 7px; } .THIS ::-webkit-scrollbar-track { display: none !important; } .THIS ::-webkit-scrollbar-thumb { border-radius: 10px; background: rgba(0,0,0,0.4); } |
Step-2: Now we will call the component.
For Single Select:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<!-- Code by CafeForce || www.cafeforce.com || support@cafeforce.com --> <aura:component> <aura:attribute name="options" type="List" default="[{'label':'Bob','value':'123'}, {'label':'Shubham','value':'234'}, {'label':'Chrissey','value':'345'}, {'label':'Jessica','value':'456','disabled': true}, {'label':'Sunny','value':'567'}]" /> <aura:attribute name="selectedValue" type="String" default="" description="Selected value in single Select" /> <c:MultiSelectCombobox options="{!v.options}" value="{!v.selectedValue}" label="Single Select Combobox"/> </aura:component> |
For Multi Select:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<!-- Code by CafeForce || www.cafeforce.com || support@cafeforce.com --> <aura:component> <aura:attribute name="options" type="List" default="[{'label':'Bob','value':'123'}, {'label':'Shubham','value':'234'}, {'label':'Chrissey','value':'345'}, {'label':'Jessica','value':'456','disabled': true}, {'label':'Sunny','value':'567'}]" /> <aura:attribute name="selectedValues" type="List" default="" description="Selected value in Multi Select" /> <c:MultiSelectCombobox options="{!v.options}" values="{!v.selectedValues}" multiSelect="true" label="Multi Select Combobox"/> </aura:component> |
Finally, our component is ready to use. Now while calling this component, you need to pass the options list and attribute in which selected value will be stored. You can also set the additional attributes and switch between single and multi select component.
How to pass the data (Option list format):
Data should be passed as Object List in the form of label and value.
Eg: [{‘label’: ‘University of Texas’, ‘value’:’UTT112′}]
To disable a value in the list:
To disable a particular element in the options list, simply add ‘disabled’: true in that element object.
Also, Check:
For any queries or suggestions regarding this post, comment below:
Cheers … 🙂
Hi,
Using the above component, i am able select multiple picklist values…but pre populating them is a issue for me.
Could you please explain that as well?
Hi Rishika,
Thanks for your query. If you are using multiSelect attribute as true (Multi select combobox). You just have to pass list of values to prepopulate in the values attribute.
Eg – values=”[‘123’, ‘234’]”
Hi,
How to get the Selected Values in Parent Component, There is either Application or Component Event Declared in your Component.
Hi Dear,
You can get list of Ids of selected values in the ‘values’ attribute. This attribute has dual behavior. To prepopulate values or to get selected values list. There is no event fired right now.
Hi,
I used above component for multi select picklist, i passed values it is showing my values currectly which is fine, but on selecting a value i am getting error “This page has an error. You might just need to refresh it. First, would you give us some details? (We’re reporting this as error ID: -2081392871)”
I checked by debugging “selectItemHelper” helper method i can see selected values currectly but I don’t why that error is occuring each time i select value.
Please help on this.
Hi Shaikh,
Can you please tell me how you are passing the data or can you please share the component calling and data passing code here. Besides, try using try-catch and console the issue.
It has a call to event.preventDefault();, But the function hasn’t ‘event’ parameter so I get an ‘[NoErrorObjectAvailable] Script error.’ error message. The function Helper => blurEventHelper function.
blurEventHelper : function(component) Transform to blurEventHelper : function(component,event)
Hi Fatih,
You caught the error buddy. Thanks for the Help! Appreciated 🙂
Hi,
It is working for me. How can i use event on this?
Hi Kirit,
Create your own component type event and register it in the component file of the component where you declare attributes.
After registering the event, fire this event from the ‘selectItemHelper’ function of Helper class.
How can we use 2 multiselect picklists in one lightening component?
Hi Amol, you can use this component twice in your lightning component.
how to disable any of these options by using controller js.
Hi Ravi,
You just need to set attribute disabled = true in the list which you are binding to component.
Eg-