Hello Coders! Welcome to another JavaScript Blog. In this, we're going to see how to create search input component using JavaScript. This will help you search various countries around the world. We get the data from an API and we're going to fetch it from javascript. This will be a good practice for you to understand how you can grasp the functionality of a search component in any website.
Here's a preview -
That being said, let us get started.
Step - 1: Like always, create 3 files - index.html, style.css and script.js.
Step - 2: Copy the below HTML code and paste it into your code editor.
HTML
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Search input component</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<main>
<div class="suggestion-box">
<div class="suggestion-input" id="suggestion-input">
<input type="text" id="suggestions" placeholder="Search any country..."/>
<span class="loader"></span>
<button id="reset"></button>
</div>
<div class="suggestion-list" id="suggestion-list"></div>
</div>
</main>
<script src="./script.js"></script>
</body>
</html>
Step - 3: Below is the CSS code for styling.
CSS
@import url('https://fonts.googleapis.com/css2?family=Dosis:wght@200;400;500;600;700&display=swap');
:root {
--loader-size: 52px;
}
* {
box-sizing: border-box;
font-family: 'Dosis', sans-serif;
letter-spacing: 1px;
}
body {
margin: 0;
font-size: 18px;
}
body, main {
background: linear-gradient(45deg, #2C303A, #5a5e69)
}
main {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
margin-top: 15%;
}
.suggestion-box {
width: 90%;
max-width: 300px;
position: relative;
}
.suggestion-box input {
background-color: rgba(1, 1, 1, .3);
color: white;
padding: 15px;
border: none;
outline: none;
font-size: 1em;
border-radius: 15px;
width: 100%;
transition: width .3s;
}
.suggestion-input {
position: relative;
}
.suggestion-input input, .suggestion-input .loading {
display: inline-block;
vertical-align: top;
}
.loader {
width: var(--loader-size);
height: var(--loader-size);
border: 4px solid white;
border-left-color: transparent;
border-right-color: transparent;
background-color: transparent;
border-radius: 50%;
animation: rotate 1.5s linear infinite;
position: absolute;
right: 0;
opacity: 0;
pointer-events: none;
transition: opacity .3s .15s;
}
.suggestion-input.loading input{
width: calc(100% - var(--loader-size) - 5px);
}
.suggestion-input.loading .loader {
opacity: 1;
}
.suggestion-list {
background-color: rgba(1, 1, 1, .15);
position: absolute;
top: var(--loader-size);
left: 0;
right: 0;
border-radius: 15px;
transition: transform .3s, opacity .3s;
transform: translateY(0px);
opacity: 0;
max-height: calc(var(--loader-size) * 4);
overflow: auto;
}
.suggestion-list.displayed {
opacity: 1;
transform: translateY(5px);
}
.suggestion-list .suggestion {
height: var(--loader-size);
width: 100%;
display: flex;
align-items: center;
padding: 0 15px;
color: white;
transition: background-color .3s;
cursor: pointer;
position: relative;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding-right: 40px;
}
.suggestion.error {
cursor: initial;
color: gray;
}
.suggestion > img {
height: var(--loader-size);
position: absolute;
right: 15px;
top: 0;
transform: scale(.3);
transform-origin: right;
}
.suggestion:not(.error):hover {
background-color: rgba(1, 1, 1, .4);
border-radius: 3px;
}
#reset {
width: calc(var(--loader-size));
height: calc(var(--loader-size));
background-color: rgba(1, 1, 1, .3);
position: absolute;
top: 0;
right: 0;
border: none;
border-radius: 50%;
border: 2px solid gray;
background-color: transparent;
outline: none;
cursor: pointer;
z-index: 3;
transform: scale(0);
transition: transform .3s;
}
#reset.displayed {
transform: scale(.5);
}
#reset::before, #reset::after {
content: "";
position: absolute;
width: 50%;
height: 2px;
background-color: gray;
top: 0;
}
#reset::before {
transform-origin: top left;
transform: rotate(45deg) translateX(22px);
left: 0;
}
#reset::after {
right: 0;
transform-origin: bottom right;
transform: rotate(-45deg) translateX(-21px);
}
#reset:hover {
border-color: white;
}
#reset:hover::after, #reset:hover::before {
background-color: white;
}
@keyframes rotate {
0% {
transform: scale(.5) rotateZ(0deg);
}
100% {
transform: scale(.5) rotateZ(360deg);
}
}
Step - 4: Below is the JavaScript code which is the most important part in this Search Component. In this, you will see that there are various functions that are used to perform various actions. Firstly we use DOM elements to store some of the elements of out HTML page. Then the function "searchCountry()" is used to search for a country according to the suggesstion given from API.
"searchEvent()" will capture any event inside the textbox and call the above function for every keyup event. If you read the code, I'm sure you won't be having any basic doubt.
JS
const $ = (s) => document.querySelector(s);
const $$ = (s) => document.querySelectorAll(s);
const $$$ = (a) => Array.from(a);
async function searchCountry (sugg) { return await fetch(`https://restcountries.eu/rest/v2/name/${sugg}`)}
let timerSuggestions = null;
const suggList$ = $('#suggestion-list');
const reset$ = $('#reset');
const suggInput$ = $('#suggestions');
const suggestionsType = {
DEFAULT: "default",
ERROR: "error",
}
const toggleLoading = (isLoading) => {
if(isLoading)
$('#suggestion-input').classList.add('loading');
else
$('#suggestion-input').classList.remove('loading');
}
const createSuggestionDom = (sugg) => {
const sugg$ = document.createElement("div");
sugg$.classList.add('suggestion');
sugg$.classList.add(sugg.type);
sugg$.innerText = sugg.message;
if(sugg.flag) {
const flag$ = document.createElement("img");
flag$.src = sugg.flag;
flag$.alt = 'Image';
sugg$.appendChild(flag$);
sugg$.addEventListener('click', () => {
suggInput$.value = sugg.message;
resetApp(false);
}, false)
}
return sugg$;
}
const updateSuggestionList = (list, direct = false) => {
suggList$.innerText = '';
if(direct) {
suggList$.appendChild(createSuggestionDom(
{
message: list.message,
type: list.type
}
));
}else{
list.forEach((country) => {
suggList$.appendChild(createSuggestionDom(
{
message: country.name,
type: suggestionsType.DEFAULT,
flag: country.flag
}
));
});
}
if(list.length > 0 || direct) {
suggList$.classList.add('displayed');
reset$.classList.add('displayed');
}
}
reset$.addEventListener('click', () => {
resetApp();
}, false);
function resetApp (withInput = true) {
suggList$.classList.remove('displayed');
if(withInput) {
suggInput$.value = '';
reset$.classList.remove('displayed');
}
}
suggInput$.addEventListener('input', (e) => {
clearTimeout(timerSuggestions);
suggList$.classList.remove('displayed');
reset$.classList.remove('displayed');
if(e.target.value.length < 2) return;
timerSuggestions = setTimeout(() => {
searchEvent(e.target.value.toLowerCase());
}, 500);
}, false);
function searchEvent(searchValue) {
toggleLoading(true);
searchCountry(searchValue).then(res => {
return res.json()
}).then(data => {
toggleLoading(false);
if(data.status < 200 || data.status >= 300) {
updateSuggestionList(
{
message: data.message,
type: suggestionsType.ERROR
}, true
);
}else{
updateSuggestionList(data);
}
});
}
[...'India$'].forEach((c, i) => {
setTimeout(() => {
if(c === '$')
searchEvent(suggInput$.value.toLowerCase());
else
suggInput$.value += c;
}, i * 120)
})
And that's it. You're done.
Let me know in the comments if you have any doubt related to this.
Follow @creocodigo for more projects and web related content.
If you find this useful, below are some other posts that I am sure you'll love.