How to Create a FAQ Page Using JavaScript

Page content

Setting the Groundwork

Before we begin tackling a project in JavaScript, we need to ask ourselves what the driving reason is behind our modification. Depending on our reasons, there are many different approaches to tackling an FAQ page. An FAQ page, by definition, is a listing of frequently asked questions to which we wish to offer answers in a concise and readable manner. With this understanding, we can approach adding some flair to an otherwise boring list by using a little bit of JavaScript.

There are quite literally dozens of different approaches one could take when it comes to interaction with an FAQ page, but we want to hone in and take a close look at a particular method by which we can assist our users in finding the answer to their questions in a timely fashion. For the sake of this article, we will tackle the problem by showing all of our questions in a list and showing only the answer to the selected question when it is clicked. This gives the user complete control over only the information they would like to have access to and avoids any sort of overload. You can see an example of the technique we will be studying in use here.

Have a Pattern in Mind

Good code must be well structured, and this case is no exception. Coming up with a plan and method of attack is essential to developing a page that will be logical and easy to maintain with future modifications. Forward thinking can help a developer from writing themselves into a corner and having to completely rework their pages when things need to be adjusted. One of the best ways to pattern code is simply by extracting as much of the JavaScript from the markup as possible. This allows the pages to be rendered and styled even when JavaScript is disabled - as in the case of screen readers or old browsers.

By allowing for your pages to be displayed properly when JavaScript is not present, you are allowing for accessibility and expansion as your site grows. For this article, we will look at a very well defined structure for our markup followed by precise targeting of our selected elements through JavaScript to show and hide them as needed. To target individual elements with JavaScript, there must be reference points accessible, so we must be sure to appropriately assign attributes to the elements in a manageable way. Keep in mind, too, that we want to be able to select individual elements without scanning the entire document, if possible - thus helping our page load time.

You can see the structure of the markup we will be using in this article here:

FAQ Markup Sample

As it stands, this markup will display well formed FAQs, especially with a bit of CSS applied to make it pop visually. This is precisely what we want to achieve. Now, let’s look at how to add our interaction with as minimal a footprint as possible while still allowing for scalability.

Object Oriented JavaScript to the Rescue

If you have read any of my previous JavaScript articles (such as How to Show a Yes/No Confirmation Box in JavaScript) or blog entries, you will find that I am a huge proponent of OOP (Object Oriented Programming) practices in JavaScript as much as I am in server side code. By organizing our actions and procedures into relevant objects, our final code base can be incredibly clean, structured and well organized - not to mention extremely simple to debug and modify in the future. In the case of our FAQ section, we can use a very basic object. Let’s consider for a moment the objects of which we must keep track to assure control over our page. In its simplest breakdown, we simply need to keep a list of object pairs: each containing a single question and its relevant answer. We will begin our coding by setting up the shell for a JavaScript object that does just this:

FAQ JavaScript Object Shell

A quick glance will reveal that we can instantiate this object by passing it the ID attribute of a div (or other container) element that in turn holds all of our FAQs. When the object is created, its init() method is immediately executed, loading up the individual entries and assigning our event handlers to show and hide them as requested. We will be fleshing out those methods in a moment. Do note as well that we are storing a reference to the container object in self.holder so that we can modify or manipulate directly at any time without having to re-select that element. Now that we have our shell, we can instantiate a new FAQ object on page load that will process over the markup we previously defined.

Instantiation of the FAQ Object on Page Load

That’s all there is to it. You can quickly see how much more manageable the code base becomes when we can minimize our footprint to this level. So, as it now stands, nothing actually happens, and interaction is what we want, so now we need to flesh out our internal methods in the FAQ object.

Processing the FAQ Markup

After looking at the shell for our FAQ object, it becomes apparent that our load method will process the markup and somehow set up our page for interaction. There are actually several things that need to be done in order for the page to display as we want:

  1. Individual FAQ entries must be found
  2. Question and answer of each entry must be recognized
  3. Verify there is exactly one question and answer pair for each
  4. Assign our click actions to the questions

Since the click action (or event listener) can be a bit complicated, we will break it out into its own method (called setupListener in the shell). Everything else can be handled fairly quickly and easily by selecting all div elements within our holder and looping over them to find those labeled as “faq-entry” items. Once those elements are identified, we find the first anchor tag and assign it as the question while assigning the first child div as our answer.

Fleshing Out the FAQ.load() Method

Attaching an Onclick Listener

Simply parsing and collecting a list of all our FAQ entries is not enough. At this point, if you run your script, you will notice that all answers have been successfully hidden, but there is no way to show them again. Enter the event handler. When the user interacts with your page by clicking on an element, an event is fired. JavaScript allows us to attach a listener, or action, to that event to be excecuted only when that event is triggered. We want to tap this potential and tie a listener to every question so that, when it is clicked, its corresponding answer is shown.

In the load method, there is a call to setupListener that we need to flesh out now. If you examine the logic, you will see that this method is being called upon every question / answer pair, and we now simply need to code the action to perform:

Attach an Onclick Listener to the FAQ Entries

Because we have been so structured in our design up to this point, the action assigned to the individual questions in incredibly simple. When a given question is clicked, we simply loop over our list of all known entries and hide each of the answers - getting us back to how our page looks at initial load time. Then, once completed, we simply target the provided answer and display it to the user, since we know it is paired with the question that was clicked. This final step of the process applies the necessary user interaction to have a fully functioning FAQ page.

Future Proofing Your Code

As mentioned before, one of our goals should be to always future proof our code. By structuring our markup in a defined pattern and writing our JavaScript in an object oriented way that consolidates the FAQ actions so nicely, it will be extremely easy to add additional functionality in the future if necessary. Also, by keeping our JavaScript code separate from the markup itself, we can style and even rearrange the elements themselves without having to worry about breaking the interaction.

Planning ahead and leaving yourself some extensibility is one of the defining elements that separates good coders from those who just get by. Even if you have no plans to make future modifications to an implementation like an FAQ page, getting into the practice of always designing your code in such a way as to allow those changes, were they to arise, is a wonderful habit to form. In closing, you may review the entire code for this article in one document here:

Full FAQ JavaScript Source