Dynamic FAQ Page – A Lesson in Accessibility and Progressive Enhancement

Published by Chris Coyier

The idea is to make a question & answer style page which is embellished in functionality by JavaScript (jQuery). Each question will be shown in a box with a tag hanging from the bottom of the box. When clicked, the tag will slide out and reveal another box with the answer.

View DemoDownload Files


This is by no means a difficult thing to accomplish, especially with jQuery. But this example is great for considering the implications of what we are about to do. Our idea takes into account the majority of people who will visit the site, those using a standard browser with JavaScript enabled. But we also need to consider those using a non-standard browser like a screen reader, or those who browse the web with JavaScript disabled.

No JavaScript

In our fully functioning example, the answers are hidden from view until the answer tag is clicked. There are a number of ways to accomplish this, but we should take care to do our hiding with JavaScript, so that when JavaScript is off, the answers are not hidden. Our "answer" pull-tab also becomes a bit irrelevant with JavaScript disabled, so let's also take care to apply that via JavaScript, so it is only present when usable.

Screen Reader

We have already established we will be doing our answer-hiding with JavaScript, so no worries about hiding answers. Our only concern now is that our markup is clean and semantic. In other words, no extra junk that screen reader people don't need to see as well as a clear separation between "question" and "answer".

The Markup

Let's start with the markup then. We'll take advantage of definition lists, which I feel is a perfect match for FAQ content.

<dl class="faq">
	<dt>How much wood would a wood chuck chuck if a wood chuck could chuck wood?</dt>
	<dd class="answer"><div>1,000,000</div></dd>

Pretty clean, but there is one bad mark on our semantics rating: the extra div in the answer element. This is not entirely necessary, but it helps the smoothness of the animation we intend to do with jQuery. Long story short, if you use a function like .slideToggle, your animation will be much smoother if that element does not use any padding. We achieve the padding we need through this extra div. More info on this here.

The jQuery JavaScript

First thing first, we load the library and link to our external JavaScript file, to keep things clean. Notice we are loading jQuery from Google here, which is recommended for production. More on how and why.

<script src="http://www.google.com/jsapi"></script>
  google.load("jquery", "1.2.6");
<script src="js/faq.js"></script>

Then we write the actual code.

  1. Hide answers.
  2. Append "answer" hang-tab
  3. Apply slideToggle functionality to tab
		.append("<dd class='answer-tab-wrap'><a class='answer-tab'>Answer</a></dd>");	


dl			{ clear: both; margin: 0 0 20px 0; }

dt			{ border: 8px solid #7ac0d0; padding: 10px; background: white; 
			  position: relative; font-style: italic; }
dd.answer		{ background: white; 
			  position: relative; width: 90%; margin: 0 auto; }
dd.answer div		{ padding: 10px; border-left: 8px solid #dedede;
                         border-right: 8px solid #dedede; border-bottom: 8px solid #dedede; }
dd.answer-tab-wrap	{ margin: 0 30px 0 0; }

.answer-tab		{ background: url(images/answer-tag.png); display: block; margin: 0 0 20px 0;
                        text-indent: -9999px; width: 105px; height: 50px; float: right; }

Few things of interest here. Because we are floating the answer tab, we'll clear the float on the definition lists themselves to make sure spacing between them works out. We are also using CSS image replacement on the .answer-tab anchor links, for the most efficiency possible (image only needs to load once).


At the top of the page, you can see the results of demo with functionality. Here are the other scenarios:

JavaScript off

Answers visible, styling still makes sense.

Screen Reader

Shown as a webpage with CSS and JavaScript disabled.

Tested & Approved in

Firefox 3, Safari 4, Internet Explorer 6 & 7, Opera 9