I am working on a multi-page web app in HTML/CSS/JS + jQuery. I am trying to build a sidebar component that expands and collapses on mouseover / mouseout. The sidebar has links to other pages on the application. The expand/collapse is working nicely, except for a very specific use case, and I’m totally stumped.
I’m using a variable mini to keep track of whether the sidebar is in collapsed (mini) or expanded state. I dynamically update the sidebar width based on whether mini is true or false, so when the user moves the mouse over the sidebar, mini = false and the sidebar expands…and when the user moves the mouse out of the sidebar, mini = true and the sidebar collapses.
The bug:
-
The user hovers mouse over sidebar to expand it
-
The user clicks on a link and gets routed to a new page
-
The user keeps the mouse hovering over the sidebar, so that when they land on the new page, the mouse is still over the sidebar
-
Now, the expand/collapse function is working inversely, so that when the user moves the mouse away, the menu expands, and when the user moves the mouse into the div, the menu collapses and disappears. Frustrating!
I think what’s happening is that the sidebar is built in the collapsed state on page load by default. Somehow I need to be able to determine whether the user has the mouse hovering inside the sidebar div on page load, so I can build the sidebar accordingly. I’d super appreciate any ideas! See below for my code. I’m not able to simulate the page routing, but the overall idea should be clear. In my code example, the sidebar functions are working as intended, so I’ve included screen grabs of what happens in the actual application with the page routing enabled. See below. Thanks!
var mini = true;
const logo = $("#nav-logo");
let activeState = false;
let activePage;
let iconsArr = [
"#dashboard-icon",
"#projects-icon",
"#assess-icon",
"#config-icon",
];
let listItemsArr = [
"#dashboard-list-item",
"#projects-list-item",
"#assess-list-item",
"#config-list-item",
];
$(function() {
attachClickListeners();
});
const toggleSidebar = () => {
if (mini) {
// sidebar
$("#mySidebar").css("width", "225px");
// main
$("#main").css("margin-left", "225px");
// logo
$("#nav-logo").attr("src", "https://www.creativefabrica.com/wp-content/uploads/2018/11/Company-business-generic-logo-by-DEEMKA-STUDIO.jpg");
$("#nav-logo").css("width", "120px");
// Logo text
$("#logo-text-container").show();
// list item styling
$(".list-item").css("padding-left", "12px");
$(".list-item").css("margin-bottom", "4px");
$(".list-item-text").show();
// Active state and page
if (activePage != undefined) {
// Remove active state from non-active items
listItemsArr.forEach((item) => {
if (item[1] != activePage[0]) {
$(item).removeClass("active");
}
});
// Add active class
$(`#${activePage}-icon`).removeClass("active");
$(`#${activePage}-list-item`).addClass("active");
}
// mini variable
this.mini = false;
} else {
// sidebar
$("#mySidebar").css("width", "60px");
// main
$("#main").css("margin-left", "60px");
// logo
$("#nav-logo").attr("src", "https://www.creativefabrica.com/wp-content/uploads/2018/11/Company-business-generic-logo-by-DEEMKA-STUDIO.jpg");
$("#nav-logo").css("width", "30px");
// logo text
$("#logo-text-container").hide();
// list item styling
$(".list-item").css("padding-left", "0px");
$(".list-item").css("margin-bottom", "6px");
$(".list-item-text").hide();
// Active state and page
if (activePage != undefined) {
// Active state and page
if (activePage != undefined) {
// Remove active state from non-active items
iconsArr.forEach((item) => {
if (item[1] != activePage[0]) {
$(item).removeClass("active");
}
});
// Add active class to active item
$(`#${activePage}-icon`).addClass("active");
$(`#${activePage}-list-item`).removeClass("active");
}
}
// mini variable
this.mini = true;
}
};
const attachClickListeners = () => {
$("#dashboard-list-item").off();
$("#dashboard-list-item").on("click", () => {
if (!activeState) {
activeState = true;
}
toggleActiveState("#dashboard-icon");
activePage = "dashboard";
});
$("#projects-list-item").off();
$("#projects-list-item").on("click", () => {
if (!activeState) {
activeState = true;
}
toggleActiveState("#projects-icon");
activePage = "projects";
});
$("#assess-list-item").off();
$("#assess-list-item").on("click", () => {
if (!activeState) {
activeState = true;
}
toggleActiveState("#assess-icon");
activePage = "assess";
});
$("#config-list-item").off();
$("#config-list-item").on("click", () => {
if (!activeState) {
activeState = true;
}
toggleActiveState("#config-icon");
activePage = "config";
});
};
const toggleActiveState = (id) => {
let element = $(id);
iconsArr.forEach((item) => {
if (item === id) {
$(element).addClass("active");
} else {
$(item).removeClass("active");
}
});
};
.active {
background: lightblue;
}
main .sidebar {
position: absolute;
top: 0;
right: 25px;
font-size: 36px;
margin-left: 50px;
}
#main {
padding: 16px;
margin-left: 85px;
transition: margin-left 0.5s;
}
body {
font-family: "Poppins", sans-serif;
font-size: 14px;
font-weight: 400;
}
.sidebar {
height: 100vh;
width: 60px;
position: fixed;
transition: 0.5s ease;
left: 0;
top: 0;
/* padding-left: 15px; */
padding-top: 9px;
background-color: #fafafa;
border-right: 1px solid #e6e6e6;
white-space: nowrap;
overflow-x: hidden;
z-index: 1;
}
#nav-logo,
#logo-text {
transition: 0.5s ease;
}
.body-text {
height: 100%;
width: 100%;
margin-left: 250px;
padding-top: 1px;
padding-left: 25px;
}
#nav-logo {
width: 30px;
margin-left: 15px;
}
#logo-text-container {
margin-left: 30px;
display: none;
}
#logo-text {
font-size: 18px;
margin-block-start: 0em;
}
.list-item {
display: flex;
align-items: center;
justify-content: flex-start;
cursor: pointer;
border: 1px solid transparent;
border-radius: 100px;
margin-bottom: 7px;
}
.list-item:hover {
background: lightblue;
}
.list-item-text {
font-size: 14px;
margin-top: 15px !important;
display: none;
}
.li-text-margin-left {
margin-left: 7px;
}
#add-assessment-list-item-text {
margin-left: 4px;
}
#projects-list-item-text {
margin-left: 1px;
}
#nav-menu-items {
padding-inline-start: 7px;
width: 206px;
transition: 0.5s ease;
}
#nav-menu-items i {
font-size: 1.2rem;
/* margin-right: 0.7rem; */
padding: 10px 10px;
border-radius: 60px;
}
.list-item-text {
margin-block-start: 0.2em;
}
<link href="https://kit.fontawesome.com/ee3b09a28a.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<!-- Sidebar -->
<div id="mySidebar" class="sidebar" onmouseover="toggleSidebar()" onmouseout="toggleSidebar()">
<!-- Expanded Logo Image -->
<div id="logo-image-container">
<img src="https://www.creativefabrica.com/wp-content/uploads/2018/11/Company-business-generic-logo-by-DEEMKA-STUDIO.jpg" id="nav-logo" />
</div>
<!-- /Expanded Logo Image -->
<!-- Expanded Logo Image Text -->
<div id="logo-text-container">
<p id="logo-text">Logo Text</p>
</div>
<!-- /Expanded Logo Image Text -->
<!-- Menu Items -->
<ul id="nav-menu-items">
<li class="list-item" id="dashboard-list-item">
<i class="fa-duotone fa-table-columns" id="dashboard-icon"></i>
<p class="list-item-text li-text-margin-left">Dashboard</p>
</li>
<li class="list-item" id="projects-list-item">
<i class="fa-duotone fa-rectangle-history-circle-user" id="projects-icon"></i>
<p class="list-item-text" id="projects-list-item-text">Projects</p>
</li>
<li class="list-item" id="assess-list-item">
<i class="fa-duotone fa-address-card" id="assess-icon"></i>
<p class="list-item-text" id="add-assessment-list-item-text">
Add Assessment
</p>
</li>
<li class="list-item" id="config-list-item">
<i class="fa-duotone fa-folder-gear" id="config-icon"></i>
<p class="list-item-text li-text-margin-left">Configuration</p>
</li>
</ul>
<!-- /Menu Items -->
</div>
<!-- /Sidebar -->
<!-- Main -->
<div id="main">
<h2>Open/Collapse Sidebar on Hover</h2>
<p>Hover over any part of the sidebar to open the it.</p>
<p>To close the sidebar, move your mouse out of the sidebar.</p>
</div>
<!-- /Main -->

