Introduction for Autocomplete Text Field:
Autocomplete text functionality using vanilla JavaScript offers a seamless user experience by predicting and suggesting options as users type into input fields. This tutorial explores how to implement this feature using both an array of countries and JSON data from IT courses. The HTML structure consists of two forms, each containing an input field and a submit button. CSS is employed to style the input boxes, suggestion boxes, and scrollbar appearances, ensuring a visually appealing interface. Meanwhile, JavaScript handles the logic behind filtering suggestions based on user input, highlighting matched characters, and enabling keyboard navigation for selection.
In the implementation, the script dynamically generates suggestion lists based on the user’s input, facilitating a user-friendly experience. Additionally, it demonstrates how to handle keyboard events for navigating through suggestions and selecting options. This tutorial provides a comprehensive guide to integrating autocomplete functionality, and enhancing user interaction and efficiency in web forms.
The provided code implements autocomplete functionality using vanilla JavaScript. Let’s break down the code:
HTML Structure:
The HTML file contains two forms, each with an input field and a submit button. These forms represent different autocomplete scenarios: one for countries and another for IT courses.
Each input field has an associated suggestion box (suggest-box-array for countries and suggest-box-json for IT courses) where autocomplete suggestions will be displayed.
<!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>Autocomplete Input Text Using vanilla JavaScript</title>
<link rel="stylesheet" href="./css.css">
</head>
<body>
<h1>Autocomplete Text Using vanilla JavaScript</h1>
<h2>With Mouse Hovering & Selecting <br/>& Up Arrow/Down Arrow Activating & Enter Key Selecting <br/>& Esc Key To Cancel Selection.</h2>
<h3>Using an Array of Countries</h3>
<form action="#" autocomplete="off">
<label for="countryArrayID">Please Enter a Country Name (Start Typing):</label>
<div class="autocomplete">
<input id="countryArrayID" type="text" class="autocomplete-input-text autocomplete-input" placeholder="Country Name" />
<div class="suggest-box-array">
<!-- <ul>
<li>Afghanistan</li>
<li>Albania</li>
<li>Algeria</li>
</ul> -->
</div>
<input id="alertCountry" type="submit" value="🔎︎" class="autocomplete-submit-button autocomplete-input" />
</div>
</form>
<br/><br/><br/><br/><br/><br/><br/>
<h3>Using a JSON File of IT Courses</h3>
<form action="#" autocomplete="off">
<label for="coursesJSONID">Please Enter an IT Course Name (Start Typing):</label>
<div class="autocomplete">
<input id="coursesJSONID" type="text" class="autocomplete-input-text autocomplete-input" placeholder="Course Name" />
<div class="suggest-box-json">
<!-- <ul>
<li>HTML Bootcamp</li>
<li>CSS Complete Tutorial</li>
<li>Full Stack</li>
</ul> -->
</div>
<input id="alertCourse" type="submit" value="🔎︎" class="autocomplete-submit-button autocomplete-input" />
</div>
</form>
<script src="./js.js"></script>
</body>
</html>
CSS Styling:
CSS styles define the appearance of various elements such as input fields, suggestion boxes, and scrollbar appearances.
Classes like autocomplete, autocomplete-input, suggest-box-array, and suggest-box-json are used to style specific components.
:root{
--dark-color: #1d1d1d;
--light-color: #ffffff;
--active-color: #d51313;
--hover-color: #e9e9e9;
--width-of-autocomplete-text-input: 320px;
--width-of-button-input: 40px;
--itemHeight: 20px;
--threeitemsheight: calc((5 * var(--itemHeight)) + 18px);
}
body{
box-sizing: border-box;
text-align: center;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif
}
.autocomplete {
/*the container must be positioned relative:*/
position: relative;
display: inline-block;
width:var(--width-of-autocomplete-text-input);
border-top: 1px solid var(--dark-color);
border-left: 1px solid var(--dark-color);
border-right: 1px solid var(--dark-color);
border-bottom: 1px solid var(--dark-color);
}
label{
display: block;
text-align: center;
width:100%;
padding-bottom: 10px;
}
.autocomplete-input, .autocomplete-input:focus, .autocomplete-input:active{
padding: 5px;
font-size: 14px;
border-radius: 30px;
}
.autocomplete-input-text{
background-color: var(--light-color);
width:calc(var(--width-of-autocomplete-text-input) - 70px);
height: var(--width-of-button-input);
position: relative;
left: -25px;
top:0px;
outline: none;
border: none;
}
.autocomplete-submit-button{
background-color: var(--dark-color);
color: var(--light-color);
width: var(--width-of-button-input);
height: var(--width-of-button-input);
padding: 2px;
position: absolute;
top:5px;
right:10px;
border: none;
outline: none;
cursor: pointer;
}
.autocomplete-submit-button:hover{
background-color: var(--active-color);
}
.suggest-box-array, .suggest-box-json {
scrollbar-width: thin;
scrollbar-color: var(--dark-color) transparent;
}
.suggest-box-array::-webkit-scrollbar, .suggest-box-json::-webkit-scrollbar {
width: 5px;
height: 5px;
}
.suggest-box-array::-webkit-scrollbar-track, .suggest-box-json::-webkit-scrollbar-track {
background-clip: content-box;
border: 2px solid transparent;
border-radius: 10px;
background-color: var(--hover-color);
}
.suggest-box-array::-webkit-scrollbar-thumb, .suggest-box-json::-webkit-scrollbar-thumb {
background-color: var(--dark-color);
border-radius: 10px;
}
.suggest-box-array::-webkit-scrollbar-thumb:hover, .suggest-box-json::-webkit-scrollbar-thumb:hover {
background-color:var(--dark-color);
}
.suggest-box-array::-webkit-scrollbar-corner, .suggest-box-json::-webkit-scrollbar-corner, .suggest-box-array::-webkit-scrollbar-track, .suggest-box-json::-webkit-scrollbar-track {
background-color: var(--hover-color);
}
.autocomplete-active{
/*when navigating through the items using the arrow keys:*/
background-color: var(--active-color) !important;
color: var(--light-color);
}
/* Array */
.suggest-box-array .row{
display: flex;
outline: none;
border-bottom: none;
outline: none;
}
.suggest-box-array{
overflow-y: scroll;
position: absolute;
z-index: 99;
width:calc(var(--width-of-autocomplete-text-input) + 12px);
max-height: calc(var(--threeitemsheight) + 9px);
/*position the autocomplete items to be the same width as the container:*/
top: 50px;
left:-1px;
right: 0px;
outline: none;
}
.suggest-box-array ul{
padding: 0px;
margin: 0px;
outline: none;
}
.suggest-box-array ul li{
list-style: none;
text-align: left;
overflow-x: hidden;
white-space: nowrap;
margin-right: 5px;
cursor: pointer;
outline: none;
padding: 10px;
background-color: var(--light-color);
border-top: 1px solid var(--dark-color);
border-right: 1px solid var(--dark-color);
border-left: 1px solid var(--dark-color);
}
.suggest-box-array ul li:last-child{
border-bottom: 1px solid var(--dark-color);
}
.suggest-box-array ul li:hover{
/*when hovering an item:*/
background-color: var(--hover-color);
}
/* End of Array */
/* JSON */
.suggest-box-json .row{
display: flex;
outline: none;
border-bottom: none;
outline: none;
}
.suggest-box-json{
overflow-y: scroll;
position: absolute;
z-index: 99;
width:calc(var(--width-of-autocomplete-text-input) + 12px);
max-height: calc(var(--threeitemsheight) + 9px);
/*position the autocomplete items to be the same width as the container:*/
top: 50px;
left:-1px;
right: 0px;
outline: none;
}
.suggest-box-json ul{
padding: 0px;
margin: 0px;
outline: none;
}
.suggest-box-json ul li{
list-style: none;
text-align: left;
overflow-x: hidden;
white-space: nowrap;
margin-right: 5px;
cursor: pointer;
outline: none;
padding: 10px;
background-color: var(--light-color);
border-top: 1px solid var(--dark-color);
border-right: 1px solid var(--dark-color);
border-left: 1px solid var(--dark-color);
}
.suggest-box-json ul li:last-child{
border-bottom: 1px solid var(--dark-color);
}
.suggest-box-json ul li:hover{
/*when hovering an item:*/
background-color: var(--hover-color);
}
/* End of JSON */
JavaScript Logic for Autocomplete Text Field:
The JavaScript code handles autocomplete functionality for both arrays and JSON data.
For the array-based autocomplete, an array of countries is provided, and suggestions are filtered based on user input. Keyboard navigation (up and down arrow keys) is implemented for selecting suggestions.
For the JSON-based autocomplete, data is fetched from a JSON file containing IT course names. Suggestions are filtered similarly to array-based autocomplete, and keyboard navigation is also supported.
The filterSuggesstionsArray and filterSuggesstionsJSON functions filter suggestions based on user input and display them in the respective suggestion boxes.
The selectInputArray and selectInputJSON functions handle the selection of autocomplete suggestions and populate the respective input fields.
Additional event listeners are set up to handle click events, keyboard inputs (up, down, enter, and escape keys), and input events.
Overall, the code provides a comprehensive solution for implementing autocomplete functionality in web forms using vanilla JavaScript. It demonstrates the integration of arrays and JSON data, keyboard navigation, and visual enhancements for a seamless user experience.
//Using Array====================================================================
let suggestArray = ["Afghanistan", "Albania", "Algeria", "Andorra", "Angola", "Anguilla", "Antigua & Barbuda", "Argentina", "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan", "Bahamas", "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", "Bosnia & Herzegovina", "Botswana", "Brazil", "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burundi", "Cambodia", "Cameroon", "Canada", "Cape Verde", "Cayman Islands", "Central Arfrican Republic", "Chad", "Chile", "China", "Colombia", "Congo", "Cook Islands", "Costa Rica", "Cote D Ivoire", "Croatia", "Cuba", "Curacao", "Cyprus", "Czech Republic", "Denmark", "Djibouti", "Dominica", "Dominican Republic", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea", "Estonia", "Ethiopia", "Falkland Islands", "Faroe Islands", "Fiji", "Finland", "France", "French Polynesia", "French West Indies", "Gabon", "Gambia", "Georgia", "Germany", "Ghana", "Gibraltar", "Greece", "Greenland", "Grenada", "Guam", "Guatemala", "Guernsey", "Guinea", "Guinea Bissau", "Guyana", "Haiti", "Honduras", "Hong Kong", "Hungary", "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Isle of Man", "Israel", "Italy", "Jamaica", "Japan", "Jersey", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kosovo", "Kuwait", "Kyrgyzstan", "Laos", "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg", "Macau", "Macedonia", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", "Mauritania", "Mauritius", "Mexico", "Micronesia", "Moldova", "Monaco", "Mongolia", "Montenegro", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia", "Nauro", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand", "Nicaragua", "Niger", "Nigeria", "North Korea", "Norway", "Oman", "Pakistan", "Palau", "Palestine", "Panama", "Papua New Guinea", "Paraguay", "Peru", "Philippines", "Poland", "Portugal", "Puerto Rico", "Qatar", "Reunion", "Romania", "Russia", "Rwanda", "Saint Pierre & Miquelon", "Samoa", "San Marino", "Sao Tome and Principe", "Saudi Arabia", "Senegal", "Serbia", "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands", "Somalia", "South Africa", "South Korea", "South Sudan", "Spain", "Sri Lanka", "St Kitts & Nevis", "St Lucia", "St Vincent", "Sudan", "Suriname", "Swaziland", "Sweden", "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "Timor L'Este", "Togo", "Tonga", "Trinidad & Tobago", "Tunisia", "Turkey", "Turkmenistan", "Turks & Caicos", "Tuvalu", "Uganda", "Ukraine", "United Arab Emirates", "United Kingdom", "United States of America", "Uruguay", "Uzbekistan", "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Virgin Islands (US)", "Yemen", "Zambia", "Zimbabwe"];
const alertCountry = document.querySelector("#alertCountry");
alertCountry.addEventListener("click", () => {
if(inputBoxArray.value !== "") {
alert(inputBoxArray.value);
}
});
const suggestBoxArray = document.querySelector(".suggest-box-array");
const inputBoxArray = document.querySelector("#countryArrayID");
let currentFocusArray = -1;
inputBoxArray.addEventListener("input", filterSuggesstionsArray);
function filterSuggesstionsArray() {
let input = this.value.trim();
currentFocusArray = -1;
suggestBoxArray.innerHTML = "";
const myList = document.createElement("ul");
myList.classList.add("items");
if(input.length) {
for(let i = 0; i < suggestArray.length; i++) {
if(suggestArray[i].toLowerCase().includes(input.toLowerCase())) {
var li = document.createElement("li");
li.classList.add("item");
li.innerHTML = `${HighlightArray(suggestArray[i])}`;
li.setAttribute("onclick", `selectInputArray('${suggestArray[i]}')`);
myList.appendChild(li);
}
}
}
suggestBoxArray.appendChild(myList);
if(!suggestArray.length) {
suggestBoxArray.innerHTML = "";
}
}
function selectInputArray(country) {
inputBoxArray.value = country;
suggestBoxArray.innerHTML = "";
}
function HighlightArray(textToSearchArray) {
const searchStringArray = inputBoxArray.value.toLowerCase();
const startIndex = textToSearchArray.toLowerCase().indexOf(searchStringArray);
const HighlightedArrayText = textToSearchArray.substring(0, startIndex) + "<mark><strong>" + searchStringArray + "</strong></mark>" + textToSearchArray.substring(startIndex + searchStringArray.length);
return HighlightedArrayText;
}
/*execute a function presses a key on the keyboard:*/
inputBoxArray.addEventListener("keydown", function(e) {
if(e.keyCode == 40) { //Down
var keyDownHilghtingArray = document.querySelector(".suggest-box-array").querySelectorAll(".item");
/*and and make the current item more visible:*/
if(currentFocusArray === keyDownHilghtingArray.length - 1) {
currentFocusArray = -1;
}
/*If the arrow DOWN key is pressed,
increase the currentFocusJSON variable:*/
currentFocusArray++;
for(let i = 0; i < keyDownHilghtingArray.length; i++) {
keyDownHilghtingArray[i].classList.remove("autocomplete-active");
}
keyDownHilghtingArray[currentFocusArray].classList.add("autocomplete-active");
// scroll to your element
keyDownHilghtingArray[currentFocusArray].scrollIntoView(false);
}
if(e.keyCode == 38) { //up
var keyDownHilghtingArray = suggestBoxArray.querySelectorAll(".item");
if(currentFocusArray === -1) {
currentFocusArray = keyDownHilghtingArray.length - 1;
}
if(currentFocusArray === 0) {
currentFocusArray = keyDownHilghtingArray.length;
}
/*If the arrow UP key is pressed,
decrease the currentFocusArray variable:*/
currentFocusArray--;
/*and and make the current item more visible:*/
for(let i = 0; i < keyDownHilghtingArray.length; i++) {
keyDownHilghtingArray[i].classList.remove("autocomplete-active");
}
keyDownHilghtingArray[currentFocusArray].classList.add("autocomplete-active");
keyDownHilghtingArray[currentFocusArray].scrollIntoView(true);
}
if(e.keyCode == 13) {
/*If the ENTER key is pressed, prevent the form from being submitted*/
e.preventDefault();
if(currentFocusArray > -1) {
var keyDownHilghtingArray = suggestBoxArray.querySelectorAll(".item");
/*and simulate a click on the "active" item:*/
if(keyDownHilghtingArray) keyDownHilghtingArray[currentFocusArray].click();
}
}
if(e.keyCode == 27) {
/*If the ESC key is pressed*/
suggestBoxArray.innerHTML = "";
}
});
//End of Using Array================================================================
//Using JSON========================================================================
const suggestBoxJSON = document.querySelector(".suggest-box-json");
const inputBoxJSON = document.querySelector("#coursesJSONID");
const alertCourse = document.querySelector("#alertCourse");
let currentFocusJSON = -1;
inputBoxJSON.addEventListener("input", filterSuggesstionsJSON);
inputBoxJSON.addEventListener("click", () => {
inputBoxJSON.select();
});
alertCourse.addEventListener("click", () => {
if(inputBoxJSON.value !== "") {
alert(inputBoxJSON.value);
}
});
async function filterSuggesstionsJSON() {
const response = await fetch("./courses.json");
const KeywordsList = await response.json();
let suggest = [];
let input = this.value.trim();
if(input.length) {
suggest = KeywordsList.filter((keyword) => {
return keyword.search.toLowerCase().includes(input.toLowerCase());
});
}
displayJSON(suggest);
if(!suggest.length) {
suggestBoxJSON.innerHTML = "";
}
}
function displayJSON(suggest) {
currentFocusJSON = -1;
const content = suggest.map((list) => {
const course = list.search;
return `<li li class= "item" onclick = "selectInputJSON('${course}')" > ${HighlightJSON(course)}</li >`;
});
suggestBoxJSON.innerHTML = `<ul class= "items" > ${content.join("")}</ul>`;
}
function selectInputJSON(course) {
inputBoxJSON.value = course;
suggestBoxJSON.innerHTML = "";
}
function HighlightJSON(textToSearchJSON) {
const searchStringJSON = inputBoxJSON.value.toLowerCase();
const startIndex = textToSearchJSON.toLowerCase().indexOf(searchStringJSON);
const HighlightJSONedText = textToSearchJSON.substring(0, startIndex) + "<mark><strong>" + searchStringJSON + "</strong></mark>" + textToSearchJSON.substring(startIndex + searchStringJSON.length);
return HighlightJSONedText;
}
/*execute a function presses a key on the keyboard:*/
inputBoxJSON.addEventListener("keydown", function(e) {
if(e.keyCode == 40) { //Down
var keyDownHilghtingJSON = suggestBoxJSON.querySelectorAll(".item");
/*and and make the current item more visible:*/
if(currentFocusJSON === keyDownHilghtingJSON.length - 1) {
currentFocusJSON = -1;
}
/*If the arrow DOWN key is pressed,
increase the currentFocusJSON variable:*/
currentFocusJSON++;
for(let i = 0; i < keyDownHilghtingJSON.length; i++) {
keyDownHilghtingJSON[i].classList.remove("autocomplete-active");
}
keyDownHilghtingJSON[currentFocusJSON].classList.add("autocomplete-active");
//height of your fixed header
let yourHeight = 40;
// scroll to your element
keyDownHilghtingJSON[currentFocusJSON].scrollIntoView(false);
// now account for fixed header
var scrolledY = keyDownHilghtingJSON[currentFocusJSON].scrollY;
if(scrolledY) {
keyDownHilghtingJSON[currentFocusJSON].scroll(0, scrolledY - yourHeight);
}
}
if(e.keyCode == 38) { //up
var keyDownHilghtingJSON = suggestBoxJSON.querySelectorAll(".item");
if(currentFocusJSON === -1) {
currentFocusJSON = keyDownHilghtingJSON.length - 1;
}
if(currentFocusJSON === 0) {
currentFocusJSON = keyDownHilghtingJSON.length;
}
/*If the arrow UP key is pressed,
decrease the currentFocusJSON variable:*/
currentFocusJSON--;
/*and and make the current item more visible:*/
for(let i = 0; i < keyDownHilghtingJSON.length; i++) {
keyDownHilghtingJSON[i].classList.remove("autocomplete-active");
}
keyDownHilghtingJSON[currentFocusJSON].classList.add("autocomplete-active");
keyDownHilghtingJSON[currentFocusJSON].scrollIntoView(true);
}
if(e.keyCode == 13) {
/*If the ENTER key is pressed, prevent the form from being submitted*/
e.preventDefault();
if(currentFocusJSON > -1) {
var keyDownHilghtingJSON = document.querySelectorAll(".item");
/*and simulate a click on the "active" item:*/
if(keyDownHilghtingJSON) keyDownHilghtingJSON[currentFocusJSON].click();
}
}
if(e.keyCode == 27) {
/*If the ESC key is pressed*/
suggestBoxJSON.innerHTML = "";
}
});
//End of Using JSON==================================================================
IT Courses JSON File:
[
{
"search": "How to learn web development"
},
{
"search": "JavaScript frameworks"
},
{
"search": "CSS tips and tricks"
},
{
"search": "Front-end vs. Back-end development"
},
{
"search": "Responsive web design"
},
{
"search": "How to use Git for web development"
},
{
"search": "Web development bootcamps"
},
{
"search": "Web accessibility guidelines"
},
{
"search": "Progressive Web Apps"
},
{
"search": "UI/UX design for the web"
},
{
"search": "React.js tutorial"
},
{
"search": "Node.js frameworks"
},
{
"search": "PHP best practices"
},
{
"search": "SEO for websites"
},
{
"search": "Web performance optimization"
},
{
"search": "GraphQL API design"
},
{
"search": "WordPress theme development"
},
{
"search": "Web security best practices"
},
{
"search": "jQuery plugins"
},
{
"search": "CSS grid layouts"
},
{
"search": "Web animations with CSS and JavaScript"
},
{
"search": "Web scraping with Python"
},
{
"search": "WebRTC video chat implementation"
},
{
"search": "Responsive images"
},
{
"search": "Debugging web applications"
},
{
"search": "Web development trends in 2023"
},
{
"search": "Bootstrap responsive design"
},
{
"search": "Python web development frameworks"
},
{
"search": "RESTful API design"
},
{
"search": "Web accessibility testing"
},
{
"search": "JavaScript design patterns"
},
{
"search": "React Native app development"
},
{
"search": "CSS preprocessors"
},
{
"search": "Web performance metrics"
},
{
"search": "Web development tools for Mac"
},
{
"search": "WordPress plugin development"
},
{
"search": "Web design trends in 2023"
},
{
"search": "Database design for web applications"
},
{
"search": "User authentication and authorization"
},
{
"search": "JavaScript testing frameworks"
},
{
"search": "Web hosting providers"
},
{
"search": "Web development for tablet & mobile devices"
},
{
"search": "React Native vs Flutter"
},
{
"search": "Web scraping tools"
},
{
"search": "Ruby on Rails tutorial"
},
{
"search": "Web design principles"
},
{
"search": "JavaScript data visualization"
},
{
"search": "Vue.js components"
},
{
"search": "Web typography best practices"
},
{
"search": "Web application architecture"
},
{
"search": "React Native app performance"
},
{
"search": "CSS flexbox layouts"
},
{
"search": "ASP.NET web development"
},
{
"search": "Web accessibility audit"
},
{
"search": "Web animations using SVG"
},
{
"search": "Web development podcasts"
},
{
"search": "Responsive web design frameworks"
},
{
"search": "JavaScript unit testing"
}
]
Conclusion:
In conclusion, this tutorial has elucidated the process of implementing autocomplete text functionality using vanilla JavaScript. By leveraging arrays and JSON data, developers can offer users predictive suggestions, thereby streamlining the input process and reducing errors. Furthermore, the tutorial emphasizes the importance of accessibility, demonstrated through keyboard navigation support and visually enhanced suggestions. With this knowledge, developers can enhance their web forms with autocomplete functionality, enriching user experiences and improving usability. As the web continues to evolve, integrating such features ensures websites remain intuitive and responsive to user needs.
Autocomplete Text Using Vanilla JavaScript: With Complete Source Code