DEV Community

Cover image for How To: Build A Simple Search Bar in JavaScript
Adriana DiPietro
Adriana DiPietro

Posted on

How To: Build A Simple Search Bar in JavaScript

Hi Everyone!

Today, we will be walking through how to build a functional, yet very simple search bar in JavaScript. This mini project will also utilize CSS and HTML.

💭💭💭💭💭💭💭💭💭💭💭

Let's look at our goals:

  1. Creating Base Files
  2. Building out the Basics of the HTML File
  3. Creating Simple Data
  4. Establishing Event Listeners
  5. Showing Results on the Page
  6. Clearing Results from the Page
  7. Showing No Results/Invalid Input
  8. Testing Our Code

Now that we have a clear outline of what we need to achieve... let's get started!


Creating Base Files

Remember: this is a simple project. You may want to add and embellish this as you want. But for today's needs, we will only need three (3) files:

  1. index.js
  2. index.html
  3. style.css

We have one (1) JavaScript file which will hold our event listeners, functions, variable declarations + assignments, and our basic data.

We have one (1) HTML file which will hold our DOM elements and portray our code in a visible format onto the web page.

And we have one (1) CSS file which we will use to style our HTML elements and add some flair + creativity.

You can create these files directly in your code editor(by right clicking and choosing "new file" or using the new file button) or in your terminal:



touch index.html
touch index.js
touch style.css


Enter fullscreen mode Exit fullscreen mode

Building out the Basics of HTML

I usually utilize the standard pattern of HTML5 to get started; it looks something like this:



<!DOCTYPE html>
   <html lang="en">
      <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Search Bar</title>
        <link rel="stylesheet" href="style.css">
      </head>
      <body>
        <script src="index.js"></script>
      </body>
   </html>



Enter fullscreen mode Exit fullscreen mode

In the title tags, you may name your project anything you would like. This is not necessarily visible on the browser page, but visible as the tab label on your browser.



<title>Search Bar</title>


Enter fullscreen mode Exit fullscreen mode

Two (2) important things to initially add (and by initially, I mean right away!) are the necessary link and script tags. Get into the practice of adding a link tag of style.css file and a script tag of your index.js file as you begin to build out your HTML file.



<head>
  <link rel="stylesheet" href="style.css">
</head>


Enter fullscreen mode Exit fullscreen mode

The stylesheets should go in the head tag portion of your HTML file. This tag allows whatever styling you program in your CSS file to appear visibly on the browser.

While the script tag to your JavaScript file should go in the body tag. It is common to put it toward the bottom. It is important to connect your HTML file with any of your JS files. Your JS files will reference DOM elements from your HTML.



<body>
    <script src="index.js"></script>
</body>


Enter fullscreen mode Exit fullscreen mode

Now, we will need some elements nested in the body of our HTML. We will definitely need:

  • a form element with an input field
  • a "clear" button to clear our results
  • an unordered list element to hold our results

Here is an example:



<body>
    <div class="form-container">
              <form class="form">
                  <input id="search" type="text" class="input" placeholder="search..."/>
                  <button id="clear" class="clear-results">clear</button>
              </form>

    </div>
    <div class="results-container>
       <ul class="results-list" id="list">

       </ul>
    </div>

       <script src="index.js"></script>
    </body>



Enter fullscreen mode Exit fullscreen mode

With each element, provide a "class" name and/or "id". Make sure the class names or id names reflect what the element is doing or providing.

From outside-in, I created a div element called "form-container"; this is a regular standard in JavaScript. We want our different sections, that have specific roles, to be nested in their own containers. So, our form container contains the form and the adjacent buttons. Then, we have another div called "results-container", this will hold our results.

Within our form container, I created a form element. This holds our succeeding form elements. I created an input tag with a type of "text". This allows the user to type inside the input form. I also provided a class name, id and a placeholder. I then created a "submit" button with a type of "submit"; this button also has a class name. The text between the button tags will showcase "search" on the button in the browser. The same idea goes for the "clear" button.

Our browser should look something like this:
search bar

So, our HTML file is set: let's continue onto our JavaScript file.


Creating Simple Data

Since we are not referencing an API, as this is a simple project, we are going to create some simple data to be rendered onto the page as search results. Head into your index.js file.

I like to create data using JavaScript nested arrays. For today's example, our data is going to be people's names. So our array is going to be called "people".



const people = []


Enter fullscreen mode Exit fullscreen mode

Each array item is going to be an object --- meaning each array item is going to have a property and value.



  const people = [
    { name: 'adri'},
    { name: 'becky'},
    { name: 'chris'},
    { name: 'dillon'},
    { name: 'evan'},
    { name: 'frank'},
    { name: 'georgette'},
    { name: 'hugh'},
    { name: 'igor'},
    { name: 'jacoby'},
    { name: 'kristina'},
    { name: 'lemony'},
    { name: 'matilda'},
    { name: 'nile'},
    { name: 'ophelia'},
    { name: 'patrick'},
    { name: 'quincy'},
    { name: 'roslyn'},
    { name: 'solene'},
    { name: 'timothy'},
    { name: 'uff'},
    { name: 'violet'},
    { name: 'wyatt'},
    { name: 'x'},
    { name: 'yadri'},
    { name: 'zack'},
]



Enter fullscreen mode Exit fullscreen mode

Here is our simple data! Feel free to create an array of food, colors, TV shows... anything you want!


Establishing Event Listeners

We have to establish two (2) event listeners. An event listener waits for an event to happen (a "click", a "keystroke", "input") and then invokes an action. In this case, we need to have something happen when input is typed into the input form and when the clear button is clicked. In JavaScript, event listener syntax looks something like this:



whateverElement.addEventListener("event type", () => {

}


Enter fullscreen mode Exit fullscreen mode

So, for our input form to have an event listener attached to it, I am going to use a querySelector to retrieve the button by its class name and set it to a constant (so that it can be used later).



const searchInput = document.querySelector('.input')


Enter fullscreen mode Exit fullscreen mode

I am now going to attach the event listener to the constant we declared and assigned:



searchInput.addEventListener("input", (e) => {
    // inside, we will need to achieve a few things:
    // 1. declare and assign the value of the event's target to a variable AKA whatever is typed in the search bar
    let value = e.target.value

    // 2. check: if input exists and if input is larger than 0
    if (value && value.trim().length > 0){
        // 3. redefine 'value' to exclude white space and change input to all lowercase
         value = value.trim().toLowerCase()
        // 4. return the results only if the value of the search is included in the person's name
        // we need to write code (a function for filtering through our data to include the search input value)
    } else {
        // 5. return nothing
        // input is invalid -- show an error message or show no results

    }

}


Enter fullscreen mode Exit fullscreen mode

Let's create a foundation for the clear button:



const clearButton = document.getElementById('clear')

clearButton.addEventListener("click", () => {
    // 1. write a function that removes any previous results from the page
})


Enter fullscreen mode Exit fullscreen mode

Showing Results on the Page

To show our results, we have to ultimately iterate through our simple data and if any of the data matches the input value, then append the data to the page (visibly).

Let's create a function that first appends the results to the webpage.



// creating and declaring a function called "setList"
// setList takes in a param of "results"
function setList(results){

    for (const person of results){
        // creating a li element for each result item
        const resultItem = document.createElement('li')

        // adding a class to each item of the results
        resultItem.classList.add('result-item')

        // grabbing the name of the current point of the loop and adding the name as the list item's text
        const text = document.createTextNode(person.name)

        // appending the text to the result item
        resultItem.appendChild(text)

        // appending the result item to the list
        list.appendChild(resultItem)
    }
}


Enter fullscreen mode Exit fullscreen mode

Now, that we have written how to append the results to the page; we need to focus on figuring out what should be appended to the page.

If we go back to our event listener, we left off at #4.
We are going to call "setList()" and pass in our people array, but not the whole array. We are going to filter through the people array and only use the items of "people" whose name value's include the value of the search input.



searchInput.addEventListener("input", (e) => {
    let value = e.target.value

    if (value && value.trim().length > 0){
         value = value.trim().toLowerCase()

        //returning only the results of setList if the value of the search is included in the person's name
        setList(people.filter(person => {
            return person.name.includes(value)
        }))



Enter fullscreen mode Exit fullscreen mode

Let's test this, if we type "be" into our search bar, "becky" should appear on the page underneath the search bar.

What do you see ?


Clearing Results from the Page

To remove the results from the page, we need to call on our "list" element and remove each child because right now our result items are children elements of "list".

An easy, quick way to do this is to remove the first child of the parent element, until there is no more... we can do this using a "while" loop.

** While Loops: while the condition is still true, do the action described. **



function clearList(){
    // looping through each child of the search results list and remove each child
    while (list.firstChild){
        list.removeChild(list.firstChild)
    }
}


Enter fullscreen mode Exit fullscreen mode

We can refer to this function, clearList(), in our event listeners --



searchInput.addEventListener("input", (e) => {
    // inside, we will need to achieve a few things:
    // 1. declare and assign the value of the event's target to a variable AKA whatever is typed in the search bar
    let value = e.target.value

    // 2. check: if input exists and if input is larger than 0
    if (value && value.trim().length > 0){
        // 3. redefine 'value' to exclude white space and change input to all lowercase
         value = value.trim().toLowerCase()
        // 4. return the results only if the value of the search is included in the person's name
        // we need to write code (a function for filtering through our data to include the search input value)
    } else {
        // 5. return nothing
        clearList()

    }

}


Enter fullscreen mode Exit fullscreen mode


clearButton.addEventListener("click", () => {
    clearList()
})


Enter fullscreen mode Exit fullscreen mode

Showing No Results

Well, we have to ask ourselves, what happens if the input value renders no matches? no results? We need to tell the user exactly that!

Let's build a function called "noResults()". This function will render an error message onto the page, where the results would've been.



function noResults(){
    // create an element for the error; a list item ("li")
    const error = document.createElement('li')
    // adding a class name of "error-message" to our error element
    error.classList.add('error-message')

    // creating text for our element
    const text = document.createTextNode('No results found. Sorry!')
    // appending the text to our element
    error.appendChild(text)
    // appending the error to our list element
    list.appendChild(error)
}


Enter fullscreen mode Exit fullscreen mode

We can use this function within our setList() function:



function setList(results){
    clearList()
    for (const person of results){
        const resultItem = document.createElement('li')
        resultItem.classList.add('result-item')
        const text = document.createTextNode(person.name)
        resultItem.appendChild(text)
        list.appendChild(resultItem)
    }

    if (results.length === 0 ){
        noResults()
    }
}


Enter fullscreen mode Exit fullscreen mode

Testing Our Code

Now, that we have beautifully written JavaScript file and HTML file, loaded with event listeners, variable declarations and functions, we can test our code.

Head over to your browser... in your terminal, type:


 open index.html 

Enter fullscreen mode Exit fullscreen mode

Here is what I see... I added a title and did some slight styling...

Case # 1: No Input (yet)
no input yet

Case # 2: Results!
Image description

Case # 3: No Matching Results
Image description



Thank you so much for reading along and coding with me. I hope you learned as much as I have with this mini-JavaScript project.

Please leave comments, questions or suggestions. Let's continue to learn together.
💭💭💭💭💭💭💭💭💭💭💭💭💭💭💭

Top comments (45)

Collapse
 
jdboris profile image
Joe Boris • Edited

EDIT: Edited to sound nicer

Good article. Here are some tips...

You should define the list variable manually. You technically don't need to, because of a little-known feature that automatically defines a global variable for each HTML element with an ID, but it's a bad practice to rely on that.

It looks like you may have made a mistake in the section where you introduce clearList. Your example code still has the placeholder comment for step 4 instead of calling setList.

Your clearList function is overcomplicated. You can just use list.innerHTML = "".

Try to follow more standard conventions and patterns. Instead of setList, I would name it renderList since showing data on the page is referred to as rendering.

Checking the length of the textbox value is unnecessary, because an empty string is already falsy. if( value.trim() ) is sufficient.

I prefer to use append rather than appendChild since it's shorter.

Lastly, you can't go wrong with document.createElement, but I prefer to use innerHTML when possible since it's shorter. You just have to remember that it clears event listeners on children.

Collapse
 
am20dipi profile image
Adriana DiPietro

I appreciate the feedback, but there are ways of providing "criticism" as you claim without condescension. Yes -- there are many ways to achieve a goal with code -- we all know that. This is a beginner's ~guide~... guide meaning do things the way you would like and follow my outline to your desired effect. It's nice to see that we all can think and improve on others; but try to say it nicer. Also "shorter" does not equate to better. Sometimes "longer" improves readability, especially for beginners. Nonetheless, I appreciate you taking the time to read and comment on my post. I like continuing the conversation past the post :)

Collapse
 
zippcodder profile image
Deon Rich

I agree. Good article, great project for people still starting out.

Thread Thread
 
am20dipi profile image
Adriana DiPietro

Thank you Deon!

Collapse
 
travissanon profile image
Travis Sanon • Edited

I'd say that

function clearList() {
  list.innerHTML = ''
}
Enter fullscreen mode Exit fullscreen mode

Is easier to read than

function clearList() {
    while (list.firstChild){
        list.removeChild(list.firstChild)
    }
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
alexfstack profile image
Alex-FStack • Edited

Boris made some great points on how to improve the code, did not see anything 'condescending' in there, all positive criticism and helpful quality tips, seems you cant take any... attitude problem?

Collapse
 
eliamazzon profile image
Elia Mazzon

Italian fella here, grande grazie!

Collapse
 
am20dipi profile image
Adriana DiPietro

Thanks Elia!

Collapse
 
tannazdev profile image
TannazDev

Thank you for your good content but there's a question in my mind I just want to make sure that the "e" parameter inside of this arrow function refers to the event that is happening is that correct??

searchInput.addEventListener("input", (e) => {}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
thedevkushagra profile image
KUSHAGRA DUBEY

Yes, "e" represents the event that is happening here.

Collapse
 
safayetjamil647 profile image
Safayet Jamil

Nice article for javascript developer.

Collapse
 
am20dipi profile image
Adriana DiPietro

Thank you Safayet!

Collapse
 
thumbone profile image
Bernd Wechner

I get a 404 on that link 🤔

 
thumbone profile image
Bernd Wechner

Thanks. But I'm curious, why are you posting a link to an unpublished article?

Collapse
 
gabriel_chukwu_9df4111800 profile image
Gabriel Chukwu • Edited

Nice work 👍

But, there is something that I noticed
The event listener acts per every input without refreshing, thereby giving repeated result.

I hope there could be a way to refresh the results at every input such that the result shown will only be the expected ones.

To achieve this , you just add
list.innerHTML= " "
at the toppest side before everything in the event listener code, like this

searchInput.addEventListener("input", (e) => {
//Here
list.innerHTML
// inside, we will need to achieve a few things:
// 1. declare and assign the value of the event's target to a variable AKA whatever is typed in the search bar
let value = e.target.value

// 2. check: if input exists and if input is larger than 0
if (value && value.trim().length > 0){
    // 3. redefine 'value' to exclude white space and change input to all lowercase
     value = value.trim().toLowerCase()
    // 4. return the results only if the value of the search is included in the person's name
    // we need to write code (a function for filtering through our data to include the search input value)
} else {
    // 5. return nothing
    // input is invalid -- show an error message or show no results

}
Enter fullscreen mode Exit fullscreen mode

}
Thanks.

Collapse
 
maryanne_fusco profile image
Mary Anne Fusco

Thank you, Adriana! I was struggling with a search bar for my site. It was working somewhat. This article helped me to get it to work seamlessly! Kudos to you!

Collapse
 
am20dipi profile image
Adriana DiPietro

Thank you Mary Anne! It is great you kept trying even when you faced obstacles. Congrats!!!

Collapse
 
kimo871 profile image
kimo871

Cool !

Collapse
 
am20dipi profile image
Adriana DiPietro

Thanks for commenting :)

Collapse
 
thedevkushagra profile image
KUSHAGRA DUBEY

Thanks for the Knowledge....Really Helpful

Collapse
 
am20dipi profile image
Adriana DiPietro

Thanks for the comment!