DEV Community

Cover image for Creating a Sidebar with HTML, CSS and JS
Felippe Regazio
Felippe Regazio

Posted on

Creating a Sidebar with HTML, CSS and JS

No bla bla bla. Lets do the job: To create a simple sidebar, you'll need to solve 3 main tasks:

  1. Create a proper structure (HTML)
  2. Add style and position (CSS)
  3. Add open/close behavior (JS)

[Codepen link at the end of the post]

So lets start by the HTML. We will create a div that is fixed on the right side of the screen. I'd like to add a comment about a rule i created for myself when writing medium to large HTML: Never add or organize the content directly on the "grand parent" element, this will keep you away from trouble.

<div id="sidebar1" class="sidebar">
  <div class="sidebar__content">
    <span>whatever you want</span>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

As we are writing a sidebar, we could do it with only one div, but this is not good for scalability, as i said. So, we will use the .sidebar div as the holder and .sidebar__content for content - duhhh :P

If you're thinking about accessibility (and you should), you'll maybe need the nav or the aside tag, depending on the way - and where - you're implementing your sidebar. This also would change the element role. As we are having a very basic conversation about it, i suggest you to (if you dont know about this things yet) ask google about HTML semantics and accessibility to complement this tutorial.

We will use aria attributes to manage the sidebar states, if you dont know about aria, you can start by this link: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA.

Lets suppose im adding a main sidebar on my page. So, we will use the aria-label to name the main sidebar, and the aria-hidden to manage its state (visible or not).

<div id="sidebar1" class="sidebar" aria-label="Main sidebar containing navigation links and some information" aria-hidden="true">
  <div class="sidebar__content">
    <span>whatever you want</span>
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Now we already have our structure. Lets add the style. We will use the "aria-hidden" attribute on the CSS to determine when the sidebar is visible or not. But first, lets care about the position:

body {
  min-height: 100vh;
}
/* SIDEBAR POSITION */
.sidebar {
  background-color: #f1f1f1;
  height: 100vh;
  position: fixed;
  top: 0;
  right: 0;
  min-width: 300px;
}
.sidebar__content {
  padding: 8px;
  overflow-y: scroll;
  overflow-x: hidden;
}
Enter fullscreen mode Exit fullscreen mode

At the "sidebar position" part of the css, we are telling the sidebar to be fixed on the right side of the screen, and also keep the screen height as its own height, acting like a fixed holder.

Then we determine that the content will have some padding and will be vertically scrollable when needed.

Now lets show/hide our sidebar. To do that we will translate (move) our sidebar out of the viewport. As our sidebar is on the right side, we need to move our sidebar to the right. The minimum and necessary distance that the sidebar needs to be translated is its own width, or 100% of itself.

As i said, we will use the aria-hidden as our state manager, so our rule is simple: when the sidebar has the aria-hidden true, we will move it out of the view port by translating it 100% (its whole size) to the right. When the sidebar hasn't aria-hidden or has aria-hidden false, we will remove the translate putting the sidebar back on its original position:

/* SIDEBAR HIDDEN STATE */
.sidebar[aria-hidden="true"] {
  transition: 200ms;
  transform: translateX(100%);
}
/* SIDEBAR VISIBLE STATE */
.sidebar:not([aria-hidden]),
.sidebar[aria-hidden="false"] {
  transition: 200ms;
  transform: translateX(0);
}
Enter fullscreen mode Exit fullscreen mode

Note the .sidebar:not([aria-hidden]) rule. That means that not only the aria-hidden false but also the absence of the aria-hidden attribute will show the sidebar. So you can use the JS to set true/false or add/remove on the attribute. Anyway we will avoid to remove the aria attribute, so we will manage the sidebar visibility by setting true/false on the aria-hidden attribute from a JS script.

With JS we will create a data attribute that holds a sidebar id. We will call it data-toggle-sidebar. The element with this attribute will query the document by the passed sidebar id, and - guess what - WILL TOGGLE IT by alternating the aria-hidden value u.u

Here is the code:

// Catch all the `[data-toggle-sidebar]` elements on the document.
document.querySelectorAll('[data-toggle-sidebar]').forEach(toggle => {
   // Add an event listener on those elements "click" event
   toggle.addEventListener('click', e => {
     // get the sidebar ID from the current element data attribute
     const sidebarID = toggle.dataset.toggleSidebar;
     // check if there is an element on the doc with the id
     const sidebarElement = sidebarID ? document.getElementById(sidebarID) : undefined;
     // if there is a sidebar with the passed id (data-toggle-sidebar)
     if (sidebarElement) {
        // toggle the aria-hidden state of the given sidebar
        let sidebarState = sidebarElement.getAttribute('aria-hidden');
        sidebarElement.setAttribute('aria-hidden', sidebarState == 'true' ? false : true); 
     }
   });
});
Enter fullscreen mode Exit fullscreen mode

By the commented code above you can easily know what the JS code does. In a few words: when a data-toggle-sidebar element is clicked, we will use its value as ID to search for a sidebar on the document. If the element (sidebar) exists, it will invert its aria-hidden value, toggling the sidebar visibility :)

Lets come back to our HTML and add a button to test our toggle function.
You must add the button as the example below:

<div id="sidebar1" class="sidebar" aria-label="Main sidebar containing navigation links and some information" aria-hidden="true">
  <div class="sidebar__content">
    <span>whatever you want</span>
  </div>
</div>

<button data-toggle-sidebar="sidebar1" aria-label="Toggle the document main sidebar visibility">Toggle Sidebar</button>
Enter fullscreen mode Exit fullscreen mode

Now you can add as many sidebars as you want (with different id's of course), and use the attribute data-toggle-sidebar to toggle them by passing the sidebar id as the attribute value. The sidebar will be toggled on the click event of the data-toggle-sidebar element.

At the end, you must have this result:

By here, you can improve your sidebar, adding a better support to the accessibility question, adding new features as close when clicked out of the sidebar, care about what happens when i open a new sidebar with another one already opened, a full responsive approach on the CSS, etc... This can be a cool trigger for new studies.

Cover image by Henry & Co. on Unsplash

Thats all folks.

Top comments (7)

Collapse
 
tfbiii profile image
Fred Buecker

I followed the ARIA link and this was very prominent in that page:

"Many of these widgets were later incorporated into HTML5, and developers should prefer using the correct semantic HTML element over using ARIA, if such an element exists. For instance, native elements have built-in keyboard accessibility, roles and states. However, if you choose to use ARIA, you are responsible for mimicking (the equivalent) browser behaviour in script."

Do you feel your specific implementation could be done with HTML5 vs ARIA?

Collapse
 
felipperegazio profile image
Felippe Regazio • Edited

Definitely yes, but you cannot completely get rid of ARIA. I tried to give a vague introduction to that point at: "If you're thinking about accessibility (and you should), you'll maybe need the nav or the aside tag, depending on the way - and where - you're implementing your sidebar".

If you replace the root element (div) with a "nav" tag, you'll already gain a lot in accessibility considering the HTML5 semantics, etc. The aria-hidden will be optional in that context, but you will still need the aria-label, the @bourhaouta solution would be ok using a "nav". You can carefully consider the "aside" tag if your sidebar content its not related to the page main content.

Collapse
 
bourhaouta profile image
Omar Bourhaouta

Nice đź‘Ť.
I also like to handle the toggle action from CSS itself by using labels and checkboxes with the + selector.

Collapse
 
felipperegazio profile image
Felippe Regazio

Thats also a good idea, but you would need to handle the accessibility separately, yap?

Collapse
 
bourhaouta profile image
Omar Bourhaouta

Good point, I didn't think about the accessibility!

Collapse
 
felipperegazio profile image
Felippe Regazio

Thanks Jhon!

Some comments may only be visible to logged-in visitors. Sign in to view all comments.