Expanding Search Bar Deconstructed

A tutorial on how to create a mobile-friendly and responsive expanding search bar.

ExpandingSearchBar

Maybe you have noticed the little adjustments that we did to our theme lately here on Codrops. One of the things we thought might be nice to change is the search input. We’ve put it from the sidebar into the header and we use a common effect where you have to click to expand the input. We have received many requests on explaining how we did it and today we’d like to show you how to create a search input like that from scratch. The aim is to maximize compatibility for mobile devices and older browsers (down to IE8). Although this might seem like a super-easy thing, we’ll have to apply some tricks in order to make it work properly.

Summarized, this is what we want the search component to do:

  • Initially, we only want to show a button with a search icon.
  • When clicking on the icon, we want a search input to slide out.
  • The component should be fluid, meaning that we can use it in a responsive context.
  • When we type something we want to be able to submit the form by either hitting enter or clicking on the search icon.
  • If the input is expanded and empty, and we click on the search icon, we want the input to close again.
  • We also want the input to close when we click outside of the search bar, be it empty or not.
  • Without JavaScript, we want the search bar to be shown expanded.
  • For a smoother experience on touch devices, we’ll also want to add support for touch events.

Now that we know what we want to do, let’s start with the markup.

The Markup

For the markup we need a main container, a form, the text and submit inputs, and a span for the icon:

<div id="sb-search" class="sb-search">
	<form>
		<input class="sb-search-input" placeholder="Enter your search term..." type="search" value="" name="search" id="search">
		<input class="sb-search-submit" type="submit" value="">
		<span class="sb-icon-search"></span>
	</form>
</div>

Usually, we could use a pseudo-element for the icon, but because it’s not intended to be used on replaced elements like form elements, we will simply use a span in this case.

With all the elements in place, let’s start styling them.

The CSS

Following our requirements, we should first make sure that we have a button with a search icon visible. The rest should be hidden. But let’s also think one step ahead and imagine what happens when we enlarge the search bar (the main wrapper). How do we do this? Let’s make use of overflow: hidden and expanding the width of the sb-search wrapper should reveal the input.

So, the first thing we style is the sb-search wrapper. We make it float on the right side and set the overflow to hidden. The width should naturally be 60px but since we will want to animate to a width of 100%, be will get in trouble on mobile (iOS) browsers. They don’t like to transition from a pixel-based width to a percentage-based one. They’ll simply omit the transition. So instead we define a min-width value of 60px and a width of 0%. This brilliant solution is by @julienknebel and he writes about it here: CSS transition from a fixed px width to an auto width.

We’ll also add a transition for the width and -webkit-backface-visibility: hidden to avoid some traces of the input for mobile (iOS) browsers:

.sb-search {
	position: relative;
	margin-top: 10px;
	width: 0%;
	min-width: 60px;
	height: 60px;
	float: right;
	overflow: hidden;

	-webkit-transition: width 0.3s;
	-moz-transition: width 0.3s;
	transition: width 0.3s;

	-webkit-backface-visibility: hidden;
}

Everything that is overflowing this little box, won’t be visible.

Now, let’s position the search input. We’ll set a percentage-based width so that when we expand the parent, the input will expand with it. Setting the right height, font-size and padding will ensure that the text is centered (using line-height won’t work as expected in IE8, so let’s set the paddings instead).
Setting the input to position absolute might not seem necessary, but it solves a nasty little thing that happens sometimes when closing the search: the input seems visible on the right side for a very short moment.

.sb-search-input {
	position: absolute;
	top: 0;
	right: 0;
	border: none;
	outline: none;
	background: #fff;
	width: 100%;
	height: 60px;
	margin: 0;
	z-index: 10;
	padding: 20px 65px 20px 20px;
	font-family: inherit;
	font-size: 20px;
	color: #2c3e50;
}

input[type="search"].sb-search-input {
	-webkit-appearance: none;
	-webkit-border-radius: 0px;
}

Additionally, we are removing the default styles of the search input for WebKit browsers.

Let’s define the color of the placeholder text with these vendor-specific rules:

.sb-search-input::-webkit-input-placeholder {
	color: #efb480;
}

.sb-search-input:-moz-placeholder {
	color: #efb480;
}

.sb-search-input::-moz-placeholder {
	color: #efb480;
}

.sb-search-input:-ms-input-placeholder {
	color: #efb480;
}

Now, let’s take care of the search icon button and the submit input. We know that we want them in the same place, so let’s position them on the right corner and set the same dimensions. Since they will be on top of each other, we’ll set them to absolute positioning:

.sb-icon-search,
.sb-search-submit  {
	width: 60px;
	height: 60px;
	display: block;
	position: absolute;
	right: 0;
	top: 0;
	padding: 0;
	margin: 0;
	line-height: 60px;
	text-align: center;
	cursor: pointer;
}

Initially, we will want to have the icon button clickable. Then, when we open the input, we want the submit input to be clickable. So, well set the z-index of the submit input to -1 in the beginning and make it transparent, so that we always see the search icon span:

.sb-search-submit {
	background: #fff; /* IE needs this */
	-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; /* IE 8 */
    filter: alpha(opacity=0); /* IE 5-7 */
    opacity: 0;
	color: transparent;
	border: none;
	outline: none;
	z-index: -1;
}

Why not just setting the background to transparent? That does not seem to work nicely in IE because the element is not clickable like that. So we use a solid background color and set the opacity to 0 instead.

The search icon span will have a high z-index initially, because we want it to be on top of everything. We’ll use the pseudo-element :before to add the search icon:

.sb-icon-search {
	color: #fff;
	background: #e67e22;
	z-index: 90;
	font-size: 22px;
	font-family: 'icomoon';
	speak: none;
	font-style: normal;
	font-weight: normal;
	font-variant: normal;
	text-transform: none;
	-webkit-font-smoothing: antialiased;
}

.sb-icon-search:before {
	content: "e000";
}

Let’s not forget to include the web font at the beginning of our CSS:

/* Search icon by IcoMoon, made with http://icomoon.io/app/ */
@font-face {
	font-family: 'icomoon';
	src:url('../fonts/icomoon/icomoon.eot');
	src:url('../fonts/icomoon/icomoon.eot?#iefix') format('embedded-opentype'),
		url('../fonts/icomoon/icomoon.woff') format('woff'),
		url('../fonts/icomoon/icomoon.ttf') format('truetype'),
		url('../fonts/icomoon/icomoon.svg#icomoon') format('svg');
	font-weight: normal;
	font-style: normal;
}

With the styles defined the way we did, we can now simply set the width of the sb-search wrapper to be 100% when we add the sb-search-open class. Without JavaScript, we want the search input to be open by default:

.sb-search.sb-search-open,
.no-js .sb-search {
	width: 100%;
}

Let’s change the color of the search icon span and put it below the submit input by setting the z-index to a lower value:

.sb-search.sb-search-open .sb-icon-search,
.no-js .sb-search .sb-icon-search {
	background: #da6d0d;
	color: #fff;
	z-index: 11;
}

And finally, we set the submit input’s z-index to a higher value so that we can click on it:

.sb-search.sb-search-open .sb-search-submit,
.no-js .sb-search .sb-search-submit {
	z-index: 90;
}

With all the necessary styles defined, let’s do the JavaScript.

Tiny break: 📬 Want to stay up to date with frontend and trends in web design? Subscribe and get our Collective newsletter twice a tweek.

The JavaScript

Let’s start by toggling the sb-search-open class. We add the class when we click on the main wrapper (sb-search) and we remove it when we click on the submit input, only if the search input is empty. Otherwise we submit the form. In order not to trigger the class removal when we click on the input (since our trigger is the whole wrapper), we need to prevent the click event bubbling on that element. This means that clicking on the input will not cause a click being triggered on its parents.

;( function( window ) {
	
	function UISearch( el, options ) {	
		this.el = el;
		this.inputEl = el.querySelector( 'form > input.sb-search-input' );
		this._initEvents();
	}

	UISearch.prototype = {
		_initEvents : function() {
			var self = this,
				initSearchFn = function( ev ) {
					if( !classie.has( self.el, 'sb-search-open' ) ) { // open it
						ev.preventDefault();
						self.open();
					}
					else if( classie.has( self.el, 'sb-search-open' ) && /^s*$/.test( self.inputEl.value ) ) { // close it
						self.close();
					}
				}

			this.el.addEventListener( 'click', initSearchFn );
			this.inputEl.addEventListener( 'click', function( ev ) { ev.stopPropagation(); });
		},
		open : function() {
			classie.add( this.el, 'sb-search-open' );
		},
		close : function() {
			classie.remove( this.el, 'sb-search-open' );
		}
	}

	// add to global namespace
	window.UISearch = UISearch;

} )( window );

Next, we’ll need to add the events for removing the sb-search-open class when we click somewhere else, outside of our search bar. For this to work we also need to take care of the event bubbling when clicking on the main wrapper.

;( function( window ) {
	
	function UISearch( el, options ) {	
		this.el = el;
		this.inputEl = el.querySelector( 'form > input.sb-search-input' );
		this._initEvents();
	}

	UISearch.prototype = {
		_initEvents : function() {
			var self = this,
				initSearchFn = function( ev ) {
					ev.stopPropagation();
					
					if( !classie.has( self.el, 'sb-search-open' ) ) { // open it
						ev.preventDefault();
						self.open();
					}
					else if( classie.has( self.el, 'sb-search-open' ) && /^s*$/.test( self.inputEl.value ) ) { // close it
						self.close();
					}
				}

			this.el.addEventListener( 'click', initSearchFn );
			this.inputEl.addEventListener( 'click', function( ev ) { ev.stopPropagation(); });
		},
		open : function() {
			var self = this;
			classie.add( this.el, 'sb-search-open' );
			// close the search input if body is clicked
			var bodyFn = function( ev ) {
				self.close();
				this.removeEventListener( 'click', bodyFn );
			};
			document.addEventListener( 'click', bodyFn );
		},
		close : function() {
			classie.remove( this.el, 'sb-search-open' );
		}
	}

	// add to global namespace
	window.UISearch = UISearch;

} )( window );

Another thing that we want to take care of is trimming the search term.
Also, when we click on the search icon, we want the input to be focused. Since this causes some jerky transition on mobile (iOS) browsers (the keyboard will open at the same time), we will want to avoid that for this case. When we close the search bar, we’ll blur the search input. This will solve some issues on some devices that show the cursor blinking even after the input is closed.

;( function( window ) {

	// http://stackoverflow.com/a/11381730/989439
	function mobilecheck() {
		var check = false;
		(function(a){if(/(android|ipad|playbook|silk|bbd+|meego).+mobile|avantgo|bada/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)/|plucker|pocket|psp|series(4|6)0|symbian|treo|up.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera);
		return check;
	}

	// http://www.jonathantneal.com/blog/polyfills-and-prototypes/
	!String.prototype.trim && (String.prototype.trim = function() {
		return this.replace(/^s+|s+$/g, '');
	});
	
	function UISearch( el, options ) {	
		this.el = el;
		this.inputEl = el.querySelector( 'form > input.sb-search-input' );
		this._initEvents();
	}

	UISearch.prototype = {
		_initEvents : function() {
			var self = this,
				initSearchFn = function( ev ) {
					ev.stopPropagation();
					// trim its value
					self.inputEl.value = self.inputEl.value.trim();
					
					if( !classie.has( self.el, 'sb-search-open' ) ) { // open it
						ev.preventDefault();
						self.open();
					}
					else if( classie.has( self.el, 'sb-search-open' ) && /^s*$/.test( self.inputEl.value ) ) { // close it
						self.close();
					}
				}

			this.el.addEventListener( 'click', initSearchFn );
			this.inputEl.addEventListener( 'click', function( ev ) { ev.stopPropagation(); });
		},
		open : function() {
			var self = this;
			classie.add( this.el, 'sb-search-open' );
			// focus the input
			if( !mobilecheck() ) {
				this.inputEl.focus();
			}
			// close the search input if body is clicked
			var bodyFn = function( ev ) {
				self.close();
				this.removeEventListener( 'click', bodyFn );
			};
			document.addEventListener( 'click', bodyFn );
		},
		close : function() {
			this.inputEl.blur();
			classie.remove( this.el, 'sb-search-open' );
		}
	}

	// add to global namespace
	window.UISearch = UISearch;

} )( window );

For everything to work smoothly on mobile devices, we’ll need to add the respective touch events. Adding preventDefault in the initSearchFn function will prevent the touch and the click events to trigger simultaneously on touch devices.

;( function( window ) {
	
	// http://stackoverflow.com/a/11381730/989439
	function mobilecheck() {
		var check = false;
		(function(a){if(/(android|ipad|playbook|silk|bbd+|meego).+mobile|avantgo|bada/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)/|plucker|pocket|psp|series(4|6)0|symbian|treo|up.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw-(n|u)|c55/|capi|ccwa|cdm-|cell|chtm|cldc|cmd-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc-s|devi|dica|dmob|do(c|p)o|ds(12|-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(-|_)|g1 u|g560|gene|gf-5|g-mo|go(.w|od)|gr(ad|un)|haie|hcit|hd-(m|p|t)|hei-|hi(pt|ta)|hp( i|ip)|hs-c|ht(c(-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i-(20|go|ma)|i230|iac( |-|/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |/)|klon|kpt |kwc-|kyo(c|k)|le(no|xi)|lg( g|/(k|l|u)|50|54|-[a-w])|libw|lynx|m1-w|m3ga|m50/|ma(te|ui|xo)|mc(01|21|ca)|m-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|-([1-8]|c))|phil|pire|pl(ay|uc)|pn-2|po(ck|rt|se)|prox|psio|pt-g|qa-a|qc(07|12|21|32|60|-[2-7]|i-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55/|sa(ge|ma|mm|ms|ny|va)|sc(01|h-|oo|p-)|sdk/|se(c(-|0|1)|47|mc|nd|ri)|sgh-|shar|sie(-|m)|sk-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h-|v-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl-|tdg-|tel(i|m)|tim-|t-mo|to(pl|sh)|ts(70|m-|m3|m5)|tx-9|up(.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas-|your|zeto|zte-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera);
		return check;
	}
	
	// http://www.jonathantneal.com/blog/polyfills-and-prototypes/
	!String.prototype.trim && (String.prototype.trim = function() {
		return this.replace(/^s+|s+$/g, '');
	});

	function UISearch( el, options ) {	
		this.el = el;
		this.inputEl = el.querySelector( 'form > input.sb-search-input' );
		this._initEvents();
	}

	UISearch.prototype = {
		_initEvents : function() {
			var self = this,
				initSearchFn = function( ev ) {
					ev.stopPropagation();
					// trim its value
					self.inputEl.value = self.inputEl.value.trim();
					
					if( !classie.has( self.el, 'sb-search-open' ) ) { // open it
						ev.preventDefault();
						self.open();
					}
					else if( classie.has( self.el, 'sb-search-open' ) && /^s*$/.test( self.inputEl.value ) ) { // close it
						ev.preventDefault();
						self.close();
					}
				}

			this.el.addEventListener( 'click', initSearchFn );
			this.el.addEventListener( 'touchstart', initSearchFn );
			this.inputEl.addEventListener( 'click', function( ev ) { ev.stopPropagation(); });
			this.inputEl.addEventListener( 'touchstart', function( ev ) { ev.stopPropagation(); } );
		},
		open : function() {
			var self = this;
			classie.add( this.el, 'sb-search-open' );
			// focus the input
			if( !mobilecheck() ) {
				this.inputEl.focus();
			}
			// close the search input if body is clicked
			var bodyFn = function( ev ) {
				self.close();
				this.removeEventListener( 'click', bodyFn );
				this.removeEventListener( 'touchstart', bodyFn );
			};
			document.addEventListener( 'click', bodyFn );
			document.addEventListener( 'touchstart', bodyFn );
		},
		close : function() {
			this.inputEl.blur();
			classie.remove( this.el, 'sb-search-open' );
		}
	}

	// add to global namespace
	window.UISearch = UISearch;

} )( window );

Finally, for browsers that don’t support the addEventListener and removeEventListener we use Jonathan Neal’s EventListener polyfill.

// EventListener | @jon_neal | //github.com/jonathantneal/EventListener
!window.addEventListener && window.Element && (function () {
	function addToPrototype(name, method) {
		Window.prototype[name] = HTMLDocument.prototype[name] = Element.prototype[name] = method;
	}

	var registry = [];

	addToPrototype("addEventListener", function (type, listener) {
		var target = this;

		registry.unshift({
			__listener: function (event) {
				event.currentTarget = target;
				event.pageX = event.clientX + document.documentElement.scrollLeft;
				event.pageY = event.clientY + document.documentElement.scrollTop;
				event.preventDefault = function () { event.returnValue = false };
				event.relatedTarget = event.fromElement || null;
				event.stopPropagation = function () { event.cancelBubble = true };
				event.relatedTarget = event.fromElement || null;
				event.target = event.srcElement || target;
				event.timeStamp = +new Date;

				listener.call(target, event);
			},
			listener: listener,
			target: target,
			type: type
		});

		this.attachEvent("on" + type, registry[0].__listener);
	});

	addToPrototype("removeEventListener", function (type, listener) {
		for (var index = 0, length = registry.length; index < length; ++index) {
			if (registry[index].target == this && registry[index].type == type && registry[index].listener == listener) {
				return this.detachEvent("on" + type, registry.splice(index, 1)[0].__listener);
			}
		}
	});

	addToPrototype("dispatchEvent", function (eventObject) {
		try {
			return this.fireEvent("on" + eventObject.type, eventObject);
		} catch (error) {
			for (var index = 0, length = registry.length; index < length; ++index) {
				if (registry[index].target == this && registry[index].type == eventObject.type) {
					registry[index].call(this, eventObject);
				}
			}
		}
	});
})();

And that’s it! We hope you enjoyed this tutorial and find it useful!

Manoela Ilic

Manoela is the main tinkerer at Codrops. With a background in coding and passion for all things design, she creates web experiments and keeps frontend professionals informed about the latest trends.

Stay in the loop: Get your dose of frontend twice a week

Fresh news, inspo, code demos, and UI animations—zero fluff, all quality. Make your Mondays and Thursdays creative!

Feedback 98

Comments are closed.
  1. I installed the browser but when performing a search within a website does not work 🙁
    Does anyone know what should I do? Thanks

  2. I implemented this but when i start typing into the search input, i don’t get the “x” clear search icon that’s demonstrated here. What am i miss?

    • Are you using input[type=text] or input[type=search]? The latter makes Webkit render a little blue X, the former does not.

  3. I’ve used the tutorial. Yet, some odd reason it isn’t working at all. I tested it using I.E. 10 and on Dreamweaver.

  4. hello, this search bar is awsome.
    I want to create a Instagram Search and want to use it.

    Please give me reply if you allow me to sell it as a Instagram Search Engine

  5. I found that I was getting a flash of the “open” state when applying to my website. By changing
    .sb-search-input { width: 100%; }

    to

    .sb-search-input { width: 0; }

    and then creating a new rule for
    .sb-search-open .sb-search-input { width: 100%; }

    seemed to help. Hope that helps someone else.

    • also, to avoid the placeholder & input text being of a funny placement, i recommend changing it to this:
      .sb-search-input { height: auto; }

  6. This code don’t work with ie7. querySelector bug.
    I don’t understand why because I see in your html code a “polyfill” function for emulate querySelector behaviour in the bottom of the page for older browser like ie7.
    Do you have an idea ? I have 10% of visitors on my websites in ie7…

  7. how to reverse the transition of the expanding search.it transits to left now how to reverse the direction.. any clues plzzz??

    • I’ve changed:
      .sb-icon-search,
      .sb-search-submit {
      left: 0;
      right: 0; //remove this line
      }
      .sb-search-input {
      width: calc(100% – 40px); // 40px is the width of my buttons
      }

      Hope it helps.

  8. Hi!

    Thanks for some outstanding code. I have one very big challenge, which I don’t seem to be able to fix: Everything looks really great on my desktop (Mac) BUT when I’m testing it on iPad (iOS 7.x) and iPhone (iOS 7.x) the magnifying glass does not show up! I only get at white, outlined box.

    Any idea what is going on?

  9. Can anyone give a detailed explanation/instruction on how to implement this in wordpress?? That would be very much appreciated.

  10. I’m kind of a newcomer in frontend and stuff, and i don’t really understand javascript, so i was was wondering how can i get to make the search form appear already open on mobile devices, just like the one on the header of the site.

    Thanks for the attention. 🙂

  11. Hi, I have a question.

    I want to insert this in OpenCart, but I’m having trouble.

    I need to replace the name=“search” (input) for this:

    url = $(‘base’).attr(‘href’) + ‘index.php?route=product/search’;

    var search = $(‘input[name=\’search\’]’).attr(‘value’);
    if (search) {
    url += ‘&search=’ + encodeURIComponent(search);
    }
    location = url;
    });

    How do it?
    Thanks,
    Fabrício.

  12. Hello,
    I have used this for my WP website. i have created a widget with this. but i need to use the search box multiple time. can u please answer me how can i use it. asthe script is use new UISearch( document.getElementById(‘sb-search’ )); so can use it for all class? how can i use if possible?

  13. Hello! I am trying to implement this on a site with google custom search but cannot figure out how to make it function.
    I am able to place the search into the page, and it opens and closes as it should, but when I try to get the results I get this error.

    Error occurred: 404 – not found
    Apache Server at: s200478.instanturl.net

    I am using this code:
    <div class="main_container"> <ul> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> <li><a href="#">Contact</a></li> <!-- SEARCH --> <li> <div class="searchcolumn"> <div id="sb-search" class="sb-search"> <form action="search_res.php" id="cse-search-box"> <input type="hidden" name="cx" value="partner-pub-011274803776712008465:8hsc-hiyhxy" /> <input type="hidden" name="cof" value="FORID:11" /> <input type="hidden" name="ie" value="ISO-8859-1" /> <input class="sb-search-input" placeholder="Search RCPT" type="text" value="" name="search" id="search"> <input class="sb-search-submit" type="submit" value=""> <span class="sb-icon-search"></span> </form> </div> </div> </div> <script src="js/classie.js"></script> <script src="js/uisearch.js"></script> <script> new UISearch( document.getElementById( 'sb-search' ) ); </script>

    Does anyone have experience with implementing this search form and GCS? I am at my wits end on this and have tried 100 different tests, but no luck. Can anyone share their eperience with this and point me in the direction of a sample page that ues this awesome search with google search,

    Any and all help is greatly appreciated.
    Thanks in advance for any insight.
    Grace

  14. Hi. Excellent code but your search at the top of your page doesn’t appear to work in IE8. Is this correct?

  15. Very useful piece of code. Would be cool if you guys could base a WP theme on the same styling and type of functionality.

  16. Thank you for a fantastic and informative tutorial. I’m using this on a project now, I particularly like the attention to detail with regards to .no-js classes. Nice one.

  17. This is probably the best tutorial I’ve seen on the subject after extensive search… It’s so good that I cannot implement it haha but im kind of a noob with js. Trying to use this on a wordpress site but cant seem to figure it out.

  18. Hi and thank u for this tutorial
    ive tried to make this in oc3.0.2 but i couldnt, can u tell me exaclty where exactly i have to upload those files?
    thank u

  19. getting: can not read addeventlistner of null

    Have set it up as in the downloaded files.

  20. Also getting

    cannot find UISEARCH in console

    new UISearch( document.getElementById( ‘sb-search’ ) );