Introduction
A sidebar menu that doesn’t visually highlight the current page leaves users guessing where they are in your app. This guide shows how to make a sidebar menu item active on click using jQuery — automatically applying an active class to the current page’s link, including support for nested treeview-style submenus like those used in the AdminLTE admin template.
Implementation
I. Prerequisites
Before you start, make sure you have:
- A web page using jQuery (or willingness to add it)
- Basic familiarity with editing HTML and JavaScript
- An AdminLTE-based layout, or any sidebar markup you can adapt the selectors to
II. Include the Required Libraries
Load jQuery, Bootstrap, and the AdminLTE JS files. Use <script> tags — not <source> — since <source> is only valid inside <video>, <audio>, or <picture> elements and will not execute JavaScript:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/js/bootstrap.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/admin-lte/2.3.11/js/app.min.js"></script>
Note: This example uses AdminLTE 2.3.11 to match the original template’s markup (
sidebar-menu,treeview-menuclasses). If you’re starting a new project, check whether a newer AdminLTE version is a better fit, since the class names and structure can differ between major versions.
III. Add the Active-Class Script
This script compares each menu link’s URL to the current page URL, and adds the active class to the matching item — including a separate check for nested treeview submenus:
$(document).ready(function () {
var url = window.location.href;
// Highlight top-level sidebar links
$('ul.sidebar-menu a').filter(function () {
return this.href === url;
}).parent().addClass('active');
// Highlight parent treeview when a nested link matches
$('ul.treeview-menu a').filter(function () {
return this.href === url;
}).closest('.treeview').addClass('active');
});
Wrapping the logic in $(document).ready(...) ensures it only runs once the full page has loaded, so it doesn’t try to match links before they exist in the DOM.
IV. Build the Sidebar Menu HTML
Here’s a working sidebar structure. Each <a> tag’s href should point to a real page on your site — when that page loads, the script above will detect the match and apply the active class automatically:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Admin Dashboard</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<!-- Bootstrap 3.3.4 -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/css/bootstrap.css" rel="stylesheet" type="text/css">
<!-- FontAwesome 4.7.0 -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" rel="stylesheet" type="text/css">
<!-- Ionicons 2.0.1 -->
<link href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css" rel="stylesheet" type="text/css">
<!-- AdminLTE Theme -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/admin-lte/2.3.11/css/AdminLTE.min.css" rel="stylesheet" type="text/css">
<!-- AdminLTE Skin -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/admin-lte/2.3.11/css/skins/skin-blue.css" rel="stylesheet" type="text/css">
</head>
<body class="sidebar-mini skin-blue">
<aside class="main-sidebar">
<section class="sidebar">
<ul class="sidebar-menu">
<li class="header">MAIN NAVIGATION</li>
<li class="treeview">
<a href="#">
<i class="fa fa-dashboard"></i> <span>Dashboard</span>
<i class="fa fa-angle-left pull-right"></i>
</a>
<ul class="treeview-menu">
<li><a href="index.html"><i class="fa fa-circle-o"></i> Dashboard v1</a></li>
<li><a href="index2.html"><i class="fa fa-circle-o"></i> Dashboard v2</a></li>
</ul>
</li>
<li class="treeview">
<a href="#">
<i class="fa fa-files-o"></i> <span>Layout Options</span>
<span class="label label-primary pull-right">4</span>
</a>
<ul class="treeview-menu">
<li><a href="pages/layout/top-nav.html"><i class="fa fa-circle-o"></i> Top Navigation</a></li>
<li><a href="pages/layout/boxed.html"><i class="fa fa-circle-o"></i> Boxed</a></li>
<li><a href="pages/layout/fixed.html"><i class="fa fa-circle-o"></i> Fixed</a></li>
</ul>
</li>
<li>
<a href="pages/widgets.html">
<i class="fa fa-th"></i> <span>Widgets</span>
<small class="label pull-right bg-green">new</small>
</a>
</li>
</ul>
</section>
</aside>
<div class="container" style="padding:10px">
<!-- Page content goes here -->
</div>
<!-- Scripts -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.4/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/admin-lte/2.3.11/js/app.min.js"></script>
<script>
$(document).ready(function () {
var url = window.location.href;
$('ul.sidebar-menu a').filter(function () {
return this.href === url;
}).parent().addClass('active');
$('ul.treeview-menu a').filter(function () {
return this.href === url;
}).closest('.treeview').addClass('active');
});
</script>
</body>
</html>
V. What Was Fixed From the Original Markup
A few issues in a typical first draft of this code would stop it from working correctly:
<source>tags don’t run JavaScript. Every script include (jQuery, Bootstrap, AdminLTE, and the active-menu logic itself) needs to be inside a<script>tag, not<source>— browsers simply ignore JS placed in a<source>element.- Duplicate
<head>tags break the document structure. A page should only have one<head>opening and closing tag; nesting a second<head>inside the first produces invalid, unpredictable HTML. - jQuery was being loaded twice — once in the (invalid) head section and again near the bottom. Include it exactly once, ideally right before your closing
</body>tag for faster initial page rendering. - Loose equality (
==) was used to comparechecked/URL values in similar scripts — using strict equality (===) avoids unexpected type-coercion bugs and is generally better practice in JavaScript.
VI. Conclusion
Highlighting the active sidebar menu item comes down to comparing each link’s href against the current page URL with jQuery, then applying an active class to the matching item — with a second check to also activate any parent treeview when a nested link matches. Fixing the <source>-instead-of-<script> mistake and removing the duplicate <head> tag are what actually make this example run; without those two corrections, the script never executes at all.
Frequently Asked Questions
Why does the treeview parent need a separate check? Because clicking a nested link only matches that specific <a> tag — without the second filter targeting .treeview-menu a, the parent dropdown itself would never get the active class, even though one of its child links matches the current page.
Does this work with single-page applications (SPAs) that don’t do full page reloads? Not reliably. This approach checks window.location.href on page load, so it works well for traditional multi-page sites. For SPAs using client-side routing, you’d typically hook into the router’s navigation events instead.
Can I use this same technique outside of AdminLTE? Yes — the core logic (comparing this.href to the current URL and adding a class) works with any sidebar markup. You’d just adjust the jQuery selectors (ul.sidebar-menu, ul.treeview-menu) to match your own menu’s class names.
Talk to Our Technology Experts
Building out an admin dashboard or improving your site’s front end? Our team can help with front-end development and custom web application builds.
Connect with our technology experts.