Search Box

by Ajey

HTML

<!DOCTYPE html>
<html>
<head>
	<title>Test input</title>
	<link rel="stylesheet" type="text/css" href="./main.css">
	<script src="https://kit.fontawesome.com/a076d05399.js"></script>
	<link href="https://fonts.googleapis.com/css?family=Montserrat:400,600&display=swap" rel="stylesheet">
</head>
<body>
	<div id="root">
		
	</div>
	
	<!-- Dummy company logo -->
	<div class="brand-logo">
		<i class="fas fa-globe-africa"></i>
	</div>

	<script type="text/javascript" src="./main.js"></script>
</body>
</html>

CSS

* {
	box-sizing: border-box;
}

#root {
	position: absolute;
	top: 50px;
    left: 50px;
    right: 50px;
    bottom: 50px;
	margin: auto;
	width: 500px;
	z-index: 2;
}

#backdrop {
	/* position: absolute; */
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	margin: auto;
	background: rgba(0, 0, 0, 0.5);
	z-index: 1;
	display: none;
}


/* ========================================= Search box syles ============================= */
.search-container {
	width: 100%;
    position: relative;
    z-index: 3;
}

#search-box {
	color: #495057;
	width: inherit;
	height: 42px;
	line-height: 42px;
	outline: 0;
	font-size: 20px;
	padding: 0 30px 0 30px;
	border: 2px solid black;
	padding-left: 30px;
	transition: border .2s ease-out;
	font-family: "Montserrat";
}

#search-box::-webkit-input-placeholder {
	font-style: italic;
	font-size: 16px;
}

.search-separator {
	border-left: 2px solid #000;
}

.fa-search {
	position: absolute;
    left: 10px;
	top: 14px;
	cursor: pointer;
}

.fa-times-circle {
	position: absolute;
    right: 10px;
	top: 14px;
	cursor: pointer;
}

/* =============================== Search suggestion styles ============================= */
#suggestions-container {
	visibility: hidden;
	opacity: 0;
	position: relative;
    z-index: 3;
}

#suggestions-container.show {
	visibility: visible;
	opacity: 1;
}

#suggestions-list {
	width: inherit;
    background: #FFF;
    list-style: none;
	padding-left: 0;
	padding: 0;
	margin: 0;
	/* border: 2px solid orange; */
	border: 2px solid black;
	border-top: 0;
	border-bottom: 0;
}

.suggestion {
	color: #495057;
	cursor: pointer;
	padding: 14px 20px;
	line-height: 18px;
	font-size: 18px;
	border-bottom: 1px solid rgb(230, 230, 230);
	font-family: "Montserrat";
}

.suggestion:hover {
	background-color: rgba(94, 35, 220, 0.08);
}

.suggestion:focus {
	outline: 0;
	background-color: rgba(94, 35, 220, 0.08);
}

span.highlight{
    background-color: #ffff007a;
	font-weight: bold;
}

.suggestion-footer {
	color:...

JavaScript

// ================================= Mock Server Start =============================
var FAILURE_COEFF = 10;
var MAX_SERVER_LATENCY = 200;

function getRandomBool(n) {
  var maxRandomCoeff = 1000;
  if (n > maxRandomCoeff) n = maxRandomCoeff;
  return Math.floor(Math.random() * maxRandomCoeff) % n === 0;
}

function getSuggestions(text) {
  var pre = 'pre';
  var post = 'post';
  var results = [];
  if (getRandomBool(2)) {
    results.push(pre + text);
  }
  if (getRandomBool(2)) {
    results.push(text);
  }
  if (getRandomBool(2)) {
    results.push(text + post);
  }
  if (getRandomBool(2)) {
    results.push(pre + text + post);
  }
  return new Promise((resolve, reject) => {
    var randomTimeout = Math.random() * MAX_SERVER_LATENCY;
    setTimeout(() => {
      if (getRandomBool(FAILURE_COEFF)) {
        reject();
      } else {
        resolve(results);
      }
    }, randomTimeout);
  });
}
// ================================= Mock Server End =============================


/* ================================= Solution Description START ===========================================
I've used vanilla javascript for implementing this search widget as using a library like react or jquery would be an overkill imo. 
The search widget takes a root HTML element where it renders 
the widget and an API URL (in our case a function) to invoke on every user input.

One of my primary intent was to create this search widget like a library which can be a drop in replacement in other projects. 
The widget exposes some api's like `getSearchTokens` that returns the current search tokens or text. It can be furhter extended as desired.

One of the assumptions I've made is to have a default list of suggestions so that the suggestions can configured during the widget initialization

Based on the current code structure of the widget, it can be further extended to add more widget apis, customizations like css theme etc
================================= Solution Description END...