Creating a Sidebar with Active Links
Published: 2023-11-19 20:25:09

Suppose we want to create a sidebar menu that tracks active links.

First, let's create the sidebar container div:

```
<div id="sidebar-container">

</div>
```

Assume our data-sidebar-links are being passed from an ERB file:

```
<div id="sidebar-container" data-sidebar-links='<%= @sidebar_links %>'>

</div>
```

Now, let's set a title at the top of the sidebar:

```
<div id="sidebar-container" data-sidebar-links='<%= @sidebar_links %>'>
  <div class="sidebar-heading">
    <%= @title %>
  </div>
</div>
```

Now, we can loop through each link. We can place an href around a div containing an icon and title for the link:

```
<div id="sidebar-container" data-sidebar-links='<%= @sidebar_links %>'>
  <div class="sidebar-heading">
    <%= @title %>
  </div>
  <div id="menuContainer">
    <% @sidebar_links.each do |link| %>
      <a href="/<%= link.fetch(:path,'') %>" class="list-group-item sidebar-link">
        <i class="<%= link.fetch(:icon,'') %>"></i>
        <%= link.fetch(:title,'') %>
      </a>
    <% end %>
  </div>
</div>
```

Now, let's tackle our JS. First, we are going to add a listener for when content has loaded in the DOM to make sure we add the listeners on the sidebar at the right time:

```
document.addEventListener('DOMContentLoaded', (event) => {

});
```

Now, let's grab the url in the browser to see which link should be active. We are also going to set up a reference to the links:

```
document.addEventListener('DOMContentLoaded', (event) => {
  const currentPath = window.location.pathname;
  const sidebarLinks = document.querySelectorAll('.sidebar-link');
});
```

Now, let's loop through each link and reset their active status. To do this, we will remove the active class style from all links then reset the active class style only to the link who's href is the browser's url:

```
document.addEventListener('DOMContentLoaded', (event) => {
  const currentPath = window.location.pathname;
  const sidebarLinks = document.querySelectorAll('.sidebar-link');
  sidebarLinks.forEach((link) => {
    link.classList.remove('active');
    if (link.getAttribute('href') === currentPath) {
      link.classList.add('active');
    }
  });
});
```

Finally, we can add styling:

```
#sidebar-container {
  width: 20vw;
  height: 100vh;
  min-height: 100vh;
  background-color: black;
  color: #fff;
}
```

`#sidebar-container`: This is a CSS ID selector. It selects the HTML element with `id="sidebar-container"`. It sets the width to 20% of the viewport’s width (vw), the height to 100% of the viewport’s height (vh), and the minimum height to 100vh, ensuring that it always takes up at least the full height of the viewport. It also sets the background color to black and the text color to white.

```
#sidebar-container .sidebar-heading {
  font-size: calc(1.275rem + .3vw)!important;
  border-bottom: 1px solid #EEEEEE;
}
```

`#sidebar-container .sidebar-heading`: This is a CSS descendant selector. It selects any element with the class `.sidebar-heading` that is a descendant of `#sidebar-container`. It sets the font size using a `calc()` function, which lets you perform calculations to determine CSS property values. The `!important` declaration increases the priority of this CSS rule.

```
#sidebar-container .list-group-item {
  display: flex;
  text-decoration: none;
  color: white;
  transition: background-color 0.3s;
  border: none;
  font-size: 1rem;
}
```

`#sidebar-container .list-group-item`: This selects any element with the class `.list-group-item` that is a descendant of `#sidebar-container`. It sets the display property to flex, allowing for flexible layouts. It also removes text decoration (like underlines), sets the color to white, adds a transition effect to the background color, removes the border, and sets the font size.

```
#sidebar-container .sidebar-heading,
#sidebar-container .list-group-item {
  padding: 1.25rem;
}
```

`#sidebar-container .sidebar-heading, #sidebar-container .list-group-item`: This selects both `.sidebar-heading` and `.list-group-item` elements inside `#sidebar-container` and sets their padding.

```
#sidebar-container .list-group-item:hover,
#sidebar-container .list-group-item.active {
  background-color: #343a40;
}
```

`#sidebar-container .list-group-item:hover, #sidebar-container .list-group-item.active`: This applies styles to `.list-group-item` elements when they are being hovered over (mouse pointer is on it) or they have the `active` class.

```
#sidebar-container .list-group-item i {
  font-size: 1.2em;
}
```

`#sidebar-container .list-group-item i`: This selects i elements inside `.list-group-item` elements and sets their font size.

Hope you enjoyed creating a sidebar!