Responsive Progressive Accessible Vanilla Search

Animation of the search menu as it gets focus.

I received a design for a project recently that called for a search field hidden behind a single icon — no visible label text, no visible field, no submit button.

While I’ve seen this pattern on sites repeatedly, I feel they generally get it wrong. Relying on bloated HTML and unnecessary JavaScript libraries is just not a sustainable solution in my opinion. They are often not keyboard friendly, don’t work without JavaScript, and have other accessibility issues.

I opted to build one I could re-use. I’ve used this approach before, and for those who are practicing atomic design, this could be considered a molecule as Brad Frost demonstrates in one animated (inaccessible and low-contrast) GIF. I figured a post describing it would be useful to others.

My Requirements

I wanted a keyboard-friendly, accessible search box that uses no special elements. I also wanted to avoid unnecessary clicks to expand the search box and use it. Ideally it would work fine without CSS and/or JavaScript (yay for progressive enhancement).

My Approach

The div in the form is simply a container for role="search", because it is not allowed on the form itself (updated as of 12/16/15, this prohibition will be changing in the specs and validator soon).

The search icon (an SVG with alternative text in my version) requires some interaction in order to be of use per the design. The label element is a natural for this as it passes focus to the associated form field, saving a tab or click or tap.

I check for a blank search field to determine whether or not to keep the submit button (also an SVG with alternative text in my version) as the next tab-stop by manipulating the tabindex value. If you don’t have JavaScript enabled (for a myriad of reasons) then the the submit stays in the tab order regardless.

Since CSS sibling selectors don’t allow us to walk backward in the DOM, I pull in JavaScript to handle some visual layout by changing classes. Again, for those without JavaScript I rely on :focus selectors to make the form usable (if a bit ugly).

Similarly, if the CSS doesn’t load, the user will get a standard unstyled form that functions just as one expects. It may look ugly, but that’s fine. The SVG is really the only thing at risk of being too big or too small (depending on your browser) as the CSS controls its sizing.

The script uses one function and some event listeners. All you have to pass is the id of the search field and it will handle the rest. While I am sure it can be cleaned and/or simplified, it tested well.

I set the placeholder text to have sufficient contrast with the background color using prefixed selectors for each of Chrome, Internet Explorer and Firefox. I also adjust the opacity for Firefox thanks to a tip from PPK.

The submit button and the label are both SVG, allowing me to scale it cleanly and easily style any color changes. While I have a title and description in the SVG to be used as the accessible name, I override them (just in case the SVG is used for other things) with an aria-label.

If you zoom the page, then the form and its controls all scale as well, though the media queries may not play as well if you both scale the font-size on the body and zoom.

I discovered some interesting quirks in browser behavior, my favorite being that Safari 6 will not draw an SVG called by the use element unless the SVG appears before the use on the page. I still have to figure out why IE and Edge are putting extra tab-stops on the page.

The Result

Embedded below is a responsive progressively-enhanced accessible search control with no external dependencies. You can also visit it directly to play with the code yourself.

See the Pen Keyboard-Friendly Accessible Search by Adrian Roselli (@aardrian) on CodePen.

Feedback

There’s always room for improvement, so if you see something that can be cleaned up or you find something causing problems then ping me on the Twitters or leave a comment.

Some Initial Feedback

Some Later Feedback

7 Comments

Reply

Regarding the extra tab stops in Edge/IE, maybe this browser compatibility table can be useful: http://allyjs.io/data-tables/focusable.html

In response to Šime Vidas. Reply

Šime, that is awesome! I’m not in front of an Edge browser now to test, but I think it might be tab-stopping on the SVG. Thanks again for the reference.

aroselli; . Permalink
Reply

Great post on attribute accessibility, but for goodness sake, a magnifying glass does not always translate to “search.” I’m still baffled that we as an industry still rely on “mystery meat” icons from the 1990s.

Jason Featheringham; . Permalink
In response to Jason Featheringham. Reply

I tend to agree that magnifying glasses don’t always make sense, but like the floppy disk as an icon for Save, it looks like it will be some time before it’s replaced. In this case, the magnifying glass was in the design. Also, given how the magnifying glass performs in user groups, I didn’t push back.

aroselli; . Permalink
Reply

A nice read, will have to give this a go! Also, loosely-related, it would be interesting to see a comparative study of user metrics based on replacing the magnifying glass with an icon of binoculars.

Matthew; . Permalink
Reply

You should disable autocorrect on mobile, otherwise it looks pretty neat.

Looks like the svg could benefit from svgomg as well, but that’s probably outside the scope.

In response to Joacim Boive. Reply

Joacim, I’m not seeing anything funky from autocorrect — are you using iOS (I am on Android)? If so, a description or screen shot would be handy so I could see the effect.

I ran the SVGs through SVGOMG when I first pulled them from an icon set, then I combined them into one <svg> element, each in its own <g>. From there I added <title> and <desc> along with some ARIA for accessibility. So the shapes/paths themselves should be optimized (unless I missed a step) though the overall file size would have climbed back up.

aroselli; . Permalink

Leave a Comment or Response

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>