Choose the structure before writing JavaScript
An FAQ accordion lets visitors reveal an answer without leaving the page. For this project, each question will be a button inside a heading, followed by an answer panel. A button is important: it can receive keyboard focus and already responds to Enter and Space. You do not need to recreate those behaviors with JavaScript.
You need a text editor and a browser that supports standard HTML buttons, the hidden attribute, and basic DOM methods such as querySelectorAll and addEventListener. No framework or package installation is required, and there is no particular library version to match. Create an HTML file and a JavaScript file in the same folder; you can open the HTML file in your browser to try the project.
Give each question a matching answer
Start with an FAQ heading and a section for each question. Inside a section, put a button inside a heading element. Put the answer in a div immediately after the heading. The button’s visible text should be the full question, and the div should contain the answer as ordinary paragraphs or lists.
For the first item, give the button the class faq-question, the id faq-q1, the attribute type set to button, aria-expanded set to false, and aria-controls set to faq-a1. Give its answer div the id faq-a1 and the hidden attribute. For the next item, use a new pair of matching values, such as faq-q2 and faq-a2. The ids must be unique on the page. The aria-controls value points to the panel the button operates; aria-expanded tells assistive technology whether that panel is currently open.
The hidden attribute keeps a closed answer out of both the visual layout and normal keyboard navigation. Keep the button visible so someone can open it. If you add CSS, make the questions easy to recognize as controls and preserve a clear focus indicator. Avoid a CSS display rule that forces hidden panels to appear.
Connect the buttons with JavaScript
Load your JavaScript file with a script element that has the defer attribute. That lets the browser build the document before the script looks for FAQ buttons. In the JavaScript file, select every button with the faq-question class. For each button, read its aria-controls value and find the element with that id. If no matching panel exists, skip that button and check the spelling of the ids in your HTML.
Add a click listener to each valid button. In the listener, set a variable named willOpen to the result of checking whether the button’s aria-expanded value is not true. Then set aria-expanded to String(willOpen), and set the panel’s hidden property to !willOpen. These three actions form the entire toggle: determine the next state, announce it on the button, and show or hide the answer. Each button controls only its own panel, so several answers can remain open at once.
Use the button’s existing click behavior rather than adding separate Enter and Space listeners. Browsers dispatch a click when a focused native button is activated with those keys. Extra keyboard handlers can accidentally make a question toggle twice.
Check the result and consider a no-script fallback
Open the page and press Tab until a question receives focus. Press Enter to open it, then Space to close it. Repeat with another question and confirm that the first answer is unaffected. Check that each visible answer corresponds to a button whose aria-expanded value is true, while each hidden answer corresponds to false. Also try clicking the question text and zooming the page: the control should remain understandable and usable.
If JavaScript does not run, panels that start with the hidden attribute will stay closed. For a more resilient FAQ, begin with the answers visible in the HTML, then have the script set each panel’s hidden property to true and its button’s aria-expanded value to false during setup. Run that setup before attaching the click listeners. This way, visitors can still read the answers when scripting is unavailable.
For an FAQ that needs only independent open-and-close behavior, the native details and summary elements are another option and may need no JavaScript at all. The button approach is useful when you want to practice controlling state yourself. Whichever approach you choose, make the question clear, keep its answer nearby, and test the interaction without a mouse.



