Building a collapsible sidebar with Stimulus and Tailwind CSS06 Jul 2021
Today we’re building one of the most common elements in web design - a lefthand sidebar for navigation - using Tailwind CSS and Stimulus.js.
Our sidebar will always take up 100% of the height of the page and we’ll be able to expand and collapse the sidebar by clicking a button. The whole thing will be accomplished with just a bit of Stimulus for the expand/collapse action and a small amount of Tailwind in our markup.
Here’s what it will look like when we’re finished.
To accomplish this, we’ll start with a plain HTML file, pull in Tailwind CSS to make things look nice, and use Stimulus for interactivity.
If you’ve never seen Tailwind before, some of the classes we add for styling might feel a little odd. You don’t need any knowledge of how Stimulus works, but if you’re brand new you might want to read the Stimulus Handbook to help solidify some concepts as we go.
You can find the complete code for this project on Github.
Let’s dive in.
For simplicity, we’re just going to use a plain old HTML file and pull in Tailwind and Stimulus from a CDN. In a real project, you should use a build system but we don’t need all that to demonstrate the concept!
Let’s start with our plain HTML. Go ahead and copy and paste the below into a file called
Now we’ll add in Stimulus and make Stimulus available through
window.Stimulus. Add these script tags to the head tag, copied right from the Stimulus docs.
And then pull in Tailwind CSS from CDN, which is not recommended for uses outside of demos like this. Tailwind has extensive documentation for how to include Tailwind for just about any build system and framework you can imagine.
Perfect, now when we open
sidebar.html in our browser we should be able to access
Let’s create the sidebar layout with Tailwind now.
Building a static sidebar
<body> of your sidebar.html file with the below to add the basic structure of the sidebar to your page.
This method of adding a static sidebar uses flexbox to create two side-by-side containers, with the smaller content on the left and the content on the right. Using Tailwind, we don’t need to touch CSS at all to create the layout, instead relying entirely on existing Tailwind utility classes.
Because we want the sidebar to have a background color that stretches (at minimum) the full height of the page, we add the
min-h-screen class to the sidebar’s container. We want to keep the navigation links on the page at all times, even if the main content scrolls, so add the
sticky class to the element that wraps the navigation menu.
Our navigation links each have an icon. When we have our collapse/expand functionality in place, the collapsed sidebar will display the link icons without any text.
With the body updated, refresh the page and see the basic layout in place. Clicking on the collapse/expand icon won’t do anything just yet.
Creating the sidebar Stimulus controller
The Stimulus controller will handle collapsing and expanding the sidebar content when the user clicks the collapse/expand icon.
First, we’ll add a function that toggles the sidebar from expanded to collapsed and back again. This function will look like this:
toggle() function uses a simple if statement that checks a data attribute in the DOM to determine if the sidebar is currently expanded or collapsed and then call the collapse or expand function as appropriate. We’ll create this data attribute in the next section.
collapse() function is responsible for collapsing the expanded sidebar, and it looks like this:
Here we find the sidebar container, remove the width Tailwind class, swap out the icon for the expand icon, apply the Tailwind
sr-only utility class to hide navigation link text from the page unless the user is accessing the site with a screenreader. Last, we update the sidebar’s expanded data attribute to 0, so that the next time the collapse/expand link is clicked the
toggle function calls the
One of the wonderful things about Stimulus is that it provides a simple way to select elements from the DOM using targets. These targets take the place of selecting elements by class or id, instead relying on data attributes.
expand() function comes next, and it looks like this:
Here we simply reverse the changes our collapse function makes:
- Setting the sidebar width
- Swapping the icon
- Display link text to all users
- Set the expanded data attribute to 1 so the next click on the icon routes to collapse
Finally, we need to tell our Stimulus controller about the targets we’re using by updating the
targets definition at the top of the Stimulus controller:
With these changes in place, the
<script> tag that adds Stimulus to our page looks like this:
If you make these updates, refresh the page and click on the collapse icon you’ll notice that absolutely nothing happens. That’s because our Stimulus controller isn’t connected to the DOM yet. We’ll finish up this guide by updating our HTML to make everything work.
Connecting to the DOM
For our Stimulus controller to work, we first need to add a
controller data attribute somewhere in the HTML. In general, you want to attach the controller to the parent element for the part of the DOM you plan to change within the controller. Since the Sidebar controller makes changes to the sidebar and the elements inside of the sidebar, it makes sense to attach the controller to the top-level sidebar element:
Next up, we need a data attribute to track the current state of the sidebar (expanded or collapsed):
The last update to the
<aside> element is to tell our Stimulus controller that it is the
Next up, our collapse icon container needs a target and an action:
data-action attribute is structured as “UserAction -> ControllerName#FunctionName”. For certain elements and actions, the UserAction component is optional but for a div, an action must always be provided. Read more about actions here.
With these attributes in place, each time the sidebar icon is clicked, the
toggle() function defined in our
Here we added
sidebar-target="link" to each of the span’s that wrap the link text. Recall that in our Stimulus controller we use
linkTargets to toggle the
sr-only class as needed. This ability to easily find and modify any number of elements without relying on classes that may or may not be changed in the future is one of the things that makes Stimulus so pleasant to work with.
With that last change in place, refresh the page one last time and see that everything works as expected.
Today we learned how to use Tailwind CSS and Stimulus to create a simple sidebar that users can collapse and expand on demand.
We’re just scratching the surface of what Tailwind and Stimulus can do. To dig in further, start with:
- Tailwind’s excellent (really, excellent) documentation
- The Stimulus Handbook
- Better Stimulus for Stimulus patterns and best practices
Thanks for reading!
About the author:
I’m David - a solo founder and consultant. I write about software engineering, Ruby on Rails and the Rails-y ecosystem, product management, and the lessons I learn as I work to build sustainable SaaS businesses.
My current project is Vestimonials, an async video communication tool to help companies collect and share video testimonials from their employees and customers. I’m available for Rails, product management, and strategy consulting. Get in touch if you have questions about this article or anything else that’s on your mind.