How to use a ComboBox with autocomplete and search as you type.

dagda13

Board Regular
Joined
May 18, 2019
Messages
52
Hi,

I have a ComboBox embedded in a worksheet that references a list of items. Ie:

small cat
cat
big cat
small dog
dog
big dog


Right now when I type in 'cat' i only get 'cat' as the suggestion. What I would like is to get all items that contain 'cat'., ie., in this case:

small cat
cat
big cat

Right now I have the "Match Entry" in the ComboBox Properties set to "1 - fmMatchEntryComplete", which allows me to filter by the characters at the beginning of each item, but I can't find a setting or code that will allow me to filter for characters that are contained within the item(s), and not just at the beginning.

Is there a way to do this? Thanks!
 
Hi,
Thank you for the answer. I just skipped this part of my project for a while, ASA I will come back to it, I will let you know, about what I got. Thank you one more time.
 
Upvote 0

Excel Facts

Spell Check in Excel
Press F7 to start spell check in Excel. Be careful, by default, Excel does not check Capitalized Werds (whoops)
First of all thanks for the code, it made my life much easier and I learned from it. It works as advertised, but it keeps the value in the dropdown so when I go to use it after making a choice, I have to manually delete the text, hit enter and then the entire value list refreshes. Did I do something wrong or is there something else I need to add to make that happen.

VBA Code:
Private Sub ComboBox1_Change()

    Dim i As Long
    Dim z As Integer
    If Not IsArrow Then
        With Sheets("Form").ComboBox1
            .List = Worksheets("POCs").Range("A2", Worksheets("POCs").Cells(Rows.Count, "A").End(xlUp)).Value
            .ListRows = Application.WorksheetFunction.Min(10, .ListCount)
            .DropDown
            
            If Len(.Text) Then
                For i = .ListCount - 1 To 0 Step -1
                    If InStr(1, .List(i), .Text, vbTextCompare) = 0 Then .RemoveItem i
                Next
                .DropDown
            End If
            
        End With
    End If
   
End Sub

Private Sub ComboBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
'https://www.mrexcel.com/board/threads/how-to-use-a-combobox-with-autocomplete-and-search-as-you-type.1098277/
    IsArrow = (KeyCode = vbKeyUp) Or (KeyCode = vbKeyDown)
Debug.Print "start Keybown"
    If KeyCode = vbKeyReturn Then
        'Me.ComboBox1.List = Range("ComboBoxData").Value
        Sheets("Form").ComboBox1.List = Worksheets("POCs").Range("A2", Worksheets("POCs").Cells(Rows.Count, "A").End(xlUp)).Value
    ElseIf KeyCode = vbKeyTab Then
        'Tab key selects first displayed item or highlighted item
        With Me.ComboBox1
        
            If .ListIndex = -1 Then
                .Value = .List(0)
            Else
                .Value = .List(.ListIndex)
            End If
        End With
        KeyCode = vbKeyReturn
    End If
Debug.Print "end Keydown"
End Sub

Private Sub ComboBox1_DropButtonClick()
    With Sheets("Form").ComboBox1
        .List = Worksheets("POCs").Range("A2", Worksheets("POCs").Cells(Rows.Count, "A").End(xlUp)).Value
        If Len(.Text) Then
            For i = .ListCount - 1 To 0 Step -1
                If InStr(1, .List(i), .Text, vbTextCompare) = 0 Then .RemoveItem i
            Next
        End If
                .DropDown
                .ListRows = Application.WorksheetFunction.Min(10, .ListCount)
    End With
End Sub
 
Upvote 0
It works as advertised, but it keeps the value in the dropdown so when I go to use it after making a choice, I have to manually delete the text, hit enter and then the entire value list refreshes.
If I understand you correctly, with a value selected in the ComboBox, you want to click on the ComboBox again, click on the value and have the value deleted so that the entire list is available and displayed. This can be achieved with the ComboBox's GotFocus event.

Below is the complete code, instructions and several improvements:

1. The ListRange variable now holds the range of values used by the ComboBox's List property, and is initialised in one place instead of using the same code in different places. As coded below, the values are in Sheet1 starting at A2 to the last populated cell in column A. A named range could be assigned to ListRange.
2. The ListRowsMaximum variable stores the ComboBox's initial ListRows property value, which is the maximum number of displayed rows.

The combo box is an ActiveX Combo Box placed on Sheet1 with the following properties:

Name = ComboBox1
ListFillRange = blank
MatchEntry = 2 - fmMatchEntryNone
MatchRequired = False

Put this code in the module of the sheet containing the combo box.
VBA Code:
Option Explicit

Dim IsArrow As Boolean
Dim ListRowsMaximum As Long
Dim ListRange As Range


Private Sub Init_Settings()

    'ListRange holds the cells to use in the combobox List
    
    With Worksheets("Sheet1")
        Set ListRange = .Range("A2", .Cells(Rows.Count, "A").End(xlUp))
    End With

    'ListRowsMaximum is the original ListRows value - maximum number of displayed rows
    
    If ListRowsMaximum = 0 Then ListRowsMaximum = Me.ComboBox1.ListRows
    
End Sub


Private Sub ComboBox1_GotFocus()

    If ListRange Is Nothing Then Init_Settings
    
    'Initialise the combobox List with cell values from ListRange
    
    With Me.ComboBox1
        .List = ListRange.Value
        .ListRows = Application.WorksheetFunction.Min(ListRowsMaximum, .ListCount)
        .Text = ""
    End With
    
End Sub


Private Sub ComboBox1_DropButtonClick()
    
    If ListRange Is Nothing Then Init_Settings
    
    With Me.ComboBox1
        .List = ListRange.Value
        .ListRows = Application.WorksheetFunction.Min(ListRowsMaximum, .ListCount)
        .DropDown
    End With
    
End Sub


Private Sub ComboBox1_Change()

    Dim i As Long
    
    'Update the combobox List to only the items containing the current Text
    
    If Not IsArrow Then
        With Me.ComboBox1
            .List = ListRange.Value
            If Len(.Text) Then
                For i = .ListCount - 1 To 0 Step -1
                    If InStr(1, .List(i), .Text, vbTextCompare) = 0 Then .RemoveItem i
                Next
            End If
            .DropDown
            .ListRows = Application.WorksheetFunction.Min(ListRowsMaximum, .ListCount)
        End With
    End If
    
End Sub


Private Sub ComboBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
        
    With Me.ComboBox1
        .ListRows = Application.WorksheetFunction.Min(ListRowsMaximum, .ListCount)
    End With
        
    IsArrow = (KeyCode = vbKeyUp) Or (KeyCode = vbKeyDown)
    
    If KeyCode = vbKeyReturn Then
        Me.ComboBox1.List = ListRange.Value
    ElseIf KeyCode = vbKeyTab Then
        'Tab key selects first displayed item or highlighted item
        With Me.ComboBox1
            If .ListIndex = -1 Then
                .Value = .List(0)
            Else
                .Value = .List(.ListIndex)
            End If
        End With
        KeyCode = vbKeyReturn
    End If
    
End Sub
 
Upvote 0
Yes, the userform's module code is identical to the worksheet module code in post #7, with the addition of a UserForm_Initialize procedure. Add an (ActiveX) ComboBox control to UserForm1 with the following properties:

Name = ComboBox1
RowSource = blank
MatchEntry = 2 - fmMatchEntryNone
MatchRequired = False

The named range is "ComboBoxData".

UserForm1 module:
VBA Code:
Option Explicit

Dim IsArrow As Boolean
Dim ListRowsMaximum As Long


Private Sub UserForm_Initialize()
    With Me.ComboBox1
        ListRowsMaximum = .ListRows
        .List = Range("ComboBoxData").Value
        .ListRows = Application.WorksheetFunction.Min(ListRowsMaximum, .ListCount)
    End With
End Sub


Private Sub ComboBox1_Change()

    Dim i As Long
 
    If Not IsArrow Then
        With Me.ComboBox1
            .List = Range("ComboBoxData").Value
            If Len(.Text) Then
                For i = .ListCount - 1 To 0 Step -1
                    If InStr(1, .List(i), .Text, vbTextCompare) = 0 Then .RemoveItem i
                Next
            End If
            .DropDown
            .ListRows = Application.WorksheetFunction.Min(ListRowsMaximum, .ListCount)
        End With
    End If
 
End Sub


Private Sub ComboBox1_DropButtonClick()

    Dim i As Long
 
    With Me.ComboBox1
        .List = Range("ComboBoxData").Value
        If Len(.Text) Then
            For i = .ListCount - 1 To 0 Step -1
                If InStr(1, .List(i), .Text, vbTextCompare) = 0 Then .RemoveItem i
            Next
        End If
        .DropDown
        .ListRows = Application.WorksheetFunction.Min(ListRowsMaximum, .ListCount)
    End With
 
End Sub


Private Sub ComboBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
 
    IsArrow = (KeyCode = vbKeyUp) Or (KeyCode = vbKeyDown)
 
    If KeyCode = vbKeyReturn Then
        Me.ComboBox1.List = Range("ComboBoxData").Value
    ElseIf KeyCode = vbKeyTab Then
        'Tab key selects first displayed item or highlighted item
        With Me.ComboBox1
            If .ListIndex = -1 Then
                .Value = .List(0)
            Else
                .Value = .List(.ListIndex)
            End If
        End With
        KeyCode = vbKeyReturn
    End If
 
End Sub
Note - There is a bug in the Worksheet module code, which means that the height of the dropdown box doesn't reduce when there are fewer items than the maximum specified (the ListRows property) i.e. the 3 blank lines below 'big top' below. This has been fixed by moving the .ListRows = lines after the .Dropdown lines.

View attachment 38620View attachment 38623
John, your solution work for me perfectly. Thanks a million for help.
 
Upvote 0
In the code:
.List = Worksheets("Sheet1").Range("A2", Worksheets("Sheet1").Cells(Rows.Count, "A").End(xlUp)).Value

Is that the sheet the combobox is in or the sheet the list is in?

I'm trying to fit the code to my project and am very lost.
 
Upvote 0
Also is there a way to drag and fill the contents of cell? (you would typically click the little square in the corner of the cell).

It seems the combobox always covers it.
 
Upvote 0
In the code:
.List = Worksheets("Sheet1").Range("A2", Worksheets("Sheet1").Cells(Rows.Count, "A").End(xlUp)).Value

Is that the sheet the combobox is in or the sheet the list is in?

Referring to the following code from post #2 How to use a ComboBox with autocomplete and search as you type.:

VBA Code:
Private Sub ComboBox1_Change()

    Dim i As Long
   
    If Not IsArrow Then
        With Me.ComboBox1
            .List = Worksheets("Sheet1").Range("A2", Worksheets("Sheet1").Cells(Rows.Count, "A").End(xlUp)).Value
            .ListRows = Application.WorksheetFunction.Min(6, .ListCount)
            .DropDown
            If Len(.Text) Then
                For i = .ListCount - 1 To 0 Step -1
                    If InStr(1, .List(i), .Text, vbTextCompare) = 0 Then .RemoveItem i
                Next
                .DropDown
            End If
        End With
    End If
   
End Sub
"Sheet1" is the sheet containing cell values (A2:A<last row>) to be put into ComboBox1.

ComboBox1 is the combobox on any sheet in the same workbook as "Sheet1", but the above ComboBox1_Change event handler must be in that sheet's sheet module.

Also is there a way to drag and fill the contents of cell? (you would typically click the little square in the corner of the cell).

It seems the combobox always covers it.
Sorry, I don't know.
 
Upvote 0
If I understand you correctly, with a value selected in the ComboBox, you want to click on the ComboBox again, click on the value and have the value deleted so that the entire list is available and displayed. This can be achieved with the ComboBox's GotFocus event.

Below is the complete code, instructions and several improvements:

1. The ListRange variable now holds the range of values used by the ComboBox's List property, and is initialised in one place instead of using the same code in different places. As coded below, the values are in Sheet1 starting at A2 to the last populated cell in column A. A named range could be assigned to ListRange.
2. The ListRowsMaximum variable stores the ComboBox's initial ListRows property value, which is the maximum number of displayed rows.

The combo box is an ActiveX Combo Box placed on Sheet1 with the following properties:

Name = ComboBox1
ListFillRange = blank
MatchEntry = 2 - fmMatchEntryNone
MatchRequired = False

Put this code in the module of the sheet containing the combo box.
VBA Code:
Option Explicit

Dim IsArrow As Boolean
Dim ListRowsMaximum As Long
Dim ListRange As Range


Private Sub Init_Settings()

    'ListRange holds the cells to use in the combobox List
   
    With Worksheets("Sheet1")
        Set ListRange = .Range("A2", .Cells(Rows.Count, "A").End(xlUp))
    End With

    'ListRowsMaximum is the original ListRows value - maximum number of displayed rows
   
    If ListRowsMaximum = 0 Then ListRowsMaximum = Me.ComboBox1.ListRows
   
End Sub


Private Sub ComboBox1_GotFocus()

    If ListRange Is Nothing Then Init_Settings
   
    'Initialise the combobox List with cell values from ListRange
   
    With Me.ComboBox1
        .List = ListRange.Value
        .ListRows = Application.WorksheetFunction.Min(ListRowsMaximum, .ListCount)
        .Text = ""
    End With
   
End Sub


Private Sub ComboBox1_DropButtonClick()
   
    If ListRange Is Nothing Then Init_Settings
   
    With Me.ComboBox1
        .List = ListRange.Value
        .ListRows = Application.WorksheetFunction.Min(ListRowsMaximum, .ListCount)
        .DropDown
    End With
   
End Sub


Private Sub ComboBox1_Change()

    Dim i As Long
   
    'Update the combobox List to only the items containing the current Text
   
    If Not IsArrow Then
        With Me.ComboBox1
            .List = ListRange.Value
            If Len(.Text) Then
                For i = .ListCount - 1 To 0 Step -1
                    If InStr(1, .List(i), .Text, vbTextCompare) = 0 Then .RemoveItem i
                Next
            End If
            .DropDown
            .ListRows = Application.WorksheetFunction.Min(ListRowsMaximum, .ListCount)
        End With
    End If
   
End Sub


Private Sub ComboBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
       
    With Me.ComboBox1
        .ListRows = Application.WorksheetFunction.Min(ListRowsMaximum, .ListCount)
    End With
       
    IsArrow = (KeyCode = vbKeyUp) Or (KeyCode = vbKeyDown)
   
    If KeyCode = vbKeyReturn Then
        Me.ComboBox1.List = ListRange.Value
    ElseIf KeyCode = vbKeyTab Then
        'Tab key selects first displayed item or highlighted item
        With Me.ComboBox1
            If .ListIndex = -1 Then
                .Value = .List(0)
            Else
                .Value = .List(.ListIndex)
            End If
        End With
        KeyCode = vbKeyReturn
    End If
   
End Sub
John,

I based my code on the one you provided above and it works for the cell that the Combo Box is in. Is it possible to add a line of code to the above to have the Combo Box search feature show up in multiple cells in a column?

Previously, I had the below vba code where the Combo Box list would show up when you double clicked a cell, but it would only search the beginning of each item instead of all the characters from the text list (similar to the original post). Any thoughts how how to manipulate my code below or your code?

Private Sub Worksheet_BeforeDoubleClick _

(ByVal Target As Range, _

Cancel As Boolean)

Dim str As String

Dim cboTemp As OLEObject

Dim ws As Worksheet

Set ws = ActiveSheet



Set cboTemp = ws.OLEObjects("TempCombo")

On Error Resume Next

With cboTemp

'clear and hide the combo box

.ListFillRange = ""

.LinkedCell = ""

.Visible = False

End With

On Error GoTo errHandler

If Target.Validation.Type = 3 Then

'if the cell contains

'a data validation list

Cancel = True

Application.EnableEvents = False

'get the data validation formula

str = Target.Validation.Formula1

str = Right(str, Len(str) - 1)

With cboTemp

'show the combobox with the list

.Visible = True

.Left = Target.Left

.Top = Target.Top

.Width = Target.Width + 5

.Height = Target.Height + 5

.ListFillRange = str

.LinkedCell = Target.Address

End With

cboTemp.Activate

'open the drop down list automatically

Me.TempCombo.DropDown

End If



errHandler:

Application.EnableEvents = True

Exit Sub



End Sub

'=========================================

Private Sub TempCombo_LostFocus()

With Me.TempCombo

.Top = 10

.Left = 10

.Width = 0

.ListFillRange = ""

.LinkedCell = ""

.Visible = False

.Value = ""

End With

End Sub

'====================================

'Optional code to move to next cell

'if Tab or Enter are pressed

'from code by Ted Lanham

'***NOTE: if KeyDown causes problems,

'change to KeyUp

'Table with numbers for other keys

'such as Right Arrow (39)

'https://msdn.microsoft.com/en-us/library/aa243025(v=vs.60).aspx



Private Sub TempCombo_KeyDown(ByVal _

KeyCode As MSForms.ReturnInteger, _

ByVal Shift As Integer)

Select Case KeyCode

Case 9 'Tab

ActiveCell.Offset(0, 1).Activate

Case 13 'Enter

ActiveCell.Offset(1, 0).Activate

Case Else

'do nothing

End Select



End Sub
 
Upvote 0
@mercer31
If you're interested, here's an example of a searchable drop-down:

OR

use an add-in called "Search deList"

 
Upvote 0
Seeking some advise/assistance from the following great guide, is their code can add so if someone enters something of their own and presses tab, jumps to first item in list.
guessing has something to do with
With Me.Job
If .ListIndex = -1 Then
.Value = .List(0)
Else
.Value = .List(.ListIndex)
End If
End With
since shows the yellow triangle on .Value = .List(0)

Many thanks
John.
 
Upvote 0

Forum statistics

Threads
1,215,389
Messages
6,124,665
Members
449,178
Latest member
Emilou

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top