Dropdown toggles help make interfaces cleaner and more accessible. By hiding options that are not immediately necessary, they prevent information overload and streamline user workflows. This is especially important for side bars and responsive design, where space is at a premium.
Uses of dropdown toggles
- Forms: Collect information in a structured format while ensuring data consistency.
- Filtering and Sorting: Enable users to refine and sort data dynamically.
- Navigation: Often used in responsive designs to accommodate complex menus in limited space.
The toggle effect
In JavaScript, "toggle" generally refers to switching a value or state back and forth between two options. We typically add a display: none;
directly to the HTML content we are toggling. Then with the JavaScript click event, we can change the class to display: block;
to show the content.
Example
The HTML
To adhere to semantic HTML best practices, use the button
tag for the dropdown toggle and the nav
tag containing a ul
and li
tags for the navigation content. If your dropdown content does not use navigation links, you can use a div
tag instead.
To make the dropdown more accessible, we can add the ARIA attributes to indicate the expandable nature of the button.
<button class="toggle-button btn-styles" aria-expanded="false" aria-controls="dropdown-nav">
<span class="button-label">Dropdown Toggle</span>
<span class="toggle-icon d-flex">
<svg width="30" height="30" xmlns="http://www.w3.org/2000/svg">
<path d="M23 10L15 18 7 10" stroke="#242424" fill="none" stroke-width="2"/>
</svg>
</span>
</button>
<nav class="toggle-content" id="dropdown-nav" style="display: none;">
<ul>
<li><a href="#">Topic link 1</a></li>
<li><a href="#">Topic link 2</a></li>
<li><a href="#">Topic link 3</a></li>
<li><a href="#">Topic link 4</a></li>
<li><a href="#">Topic link 5</a></li>
</ul>
</nav>
The CSS
To normalize the button styles, I used a set of properties that override the default browser styles. I have a post on Customizing default browser button styles that goes over this in more detail.
For the button text and chevron positioning, we can use display: flex;
with justify-content: space-between;
.
To change the chevron from down to up we can use transform: rotate(180deg);
that will apply when the JavaScript adds the .closed
class on click.
<style>
.toggle-button {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
background: transparent;
border: none;
padding: 0;
margin: 0;
line-height: normal;
color: inherit;
font: inherit;
cursor: pointer;
box-sizing: border-box;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
.toggle-icon svg.closed {
transform: rotate(180deg); /* Rotates the icon 180 degrees */
}
.toggle-icon svg path {
stroke: var(--clr-primary);
}
nav.toggle-content {
margin-top: 16px;
}
</style>
The JavaScript
First we add the event listener to ensure the code inside the function only runs after the entire HTML Document has been fully loaded and parsed.
Then we select the:
.toggle-button
when clicked will run thetoggleContentVisibility
function..toggle-icon svg
to rotate the SVG icon appearance..toggle-content
to show and hide the content.
<script>
document.addEventListener("DOMContentLoaded", function () {
const toggleButton = document.querySelector(".toggle-button");
const toggleIcon = toggleButton.querySelector(".toggle-icon svg");
const toggleContent = document.querySelector(".toggle-content");
function toggleContentVisibility() {
const isCurrentlyHidden = toggleContent.style.display === "none";
toggleContent.style.display = isCurrentlyHidden ? "block" : "none";
toggleIcon.classList.toggle('closed', isCurrentlyHidden);
toggleButton.setAttribute('aria-expanded', isCurrentlyHidden);
}
toggleButton.addEventListener("click", toggleContentVisibility);
});
</script>
isCurrentlyHidden
will be a boolean (true or false) depending on whether the element's display property is none
. Now we can use this as a flag to determine whether to add the block
property and the closed
class.
To simplify the code I used a ternary operator here instead of the traditional if-else statement. This works good for less complex functions and allows you to write a conditional assignment in a single line.