Layout
Every page shares one shell: a sidebar on the left, a top bar, the content area and a footer. This page explains each part, the classes it uses and how it behaves on small screens.
The page shell
The sidebar is fixed on the left. Everything else sits in .main-col, which leaves room for the sidebar and stacks the top bar, the content and the footer.
logo
user block
<div class="app">
<aside class="sidebar" id="sidebar">
<a href="index.html" class="sb-brand">…</a>
<div class="sb-scroll"><ul class="sb-nav">…</ul></div>
<div class="sb-user-wrap">…</div>
</aside>
<!-- dims the page while the mobile menu is open -->
<div class="backdrop" id="backdrop"></div>
<div class="main-col">
<header class="topbar">…</header>
<div class="content">…</div>
<footer class="footerbar">…</footer>
</div>
</div>
Keep the ids sidebar, backdrop and burger — js/app.js uses them to open and close the menu on small screens.
Sidebar
The sidebar has three parts: the logo at the top, the menu in a scrolling area, and a user block pinned to the bottom. If the menu is taller than the screen, only the middle part scrolls.
Logo
<a href="index.html" class="sb-brand">
<div class="logo"><img src="images/favicon-white.svg" alt=""></div>
<span>ODIN <span class="brand-dot">ADMIN</span></span>
</a>
Replace the image and the name with your own. .brand-dot colours part of the name in the primary colour; leave it out for a one-colour name.
Sections and links
The menu is one list, .sb-nav. A section heading is an <li class="sb-section">; the links under it follow as <li class="nav-item"> items with an icon and a label.
<ul class="sb-nav">
<li class="sb-section">
<span class="sb-section-dot"></span>
Dashboard
</li>
<li class="nav-item">
<a href="index-analytics.html" class="nav-link">
<i class="nav-ico fas fa-chart-line"></i>
<span>Analytics</span>
</a>
</li>
</ul>
Icons are Font Awesome 6 classes. Browse them at fontawesome.com and keep to the free set.
Submenus
A link that opens a submenu gets data-toggle="submenu" and data-target pointing at the id of its panel, plus an arrow icon. The panel is a .sb-subwrap with an inner .sb-subinner (it makes the open/close slide work) and the links in .sb-subnav.
<li class="nav-item">
<a href="#" class="nav-link" aria-expanded="false" data-toggle="submenu" data-target="#reportsWrap">
<i class="nav-ico fas fa-chart-pie"></i>
<span>Reports</span>
<i class="nav-arrow fas fa-chevron-right"></i>
</a>
<div class="sb-subwrap" id="reportsWrap">
<div class="sb-subinner">
<ul class="sb-subnav">
<li><a href="reports-sales.html" class="nav-link">Sales</a></li>
<li><a href="reports-traffic.html" class="nav-link">Traffic</a></li>
</ul>
</div>
</div>
</li>
Clicking the link adds or removes open on the link and the panel and updates aria-expanded. Several submenus can be open at once.
The current page
Mark the link of the current page with active and aria-current="page". When it sits in a submenu, render that submenu open, so the page loads with it expanded:
<a href="#" class="nav-link open" aria-expanded="true" data-toggle="submenu" data-target="#reportsWrap">…</a>
<div class="sb-subwrap open" id="reportsWrap">
…
<li><a href="reports-sales.html" class="nav-link active" aria-current="page">Sales</a></li>
The template doesn't work out the current page in JavaScript — each page has these classes written in. In a back end, set them from the current route when you render the sidebar.
User block
The bottom of the sidebar shows who is signed in. .av is an avatar with initials; put an <img> inside it for a photo.
<div class="sb-user-wrap">
<div class="sb-user">
<div class="av">JD</div>
<div>
<div class="u-name">Jane Doe</div>
<div class="u-role">Administrator</div>
</div>
</div>
</div>
Top bar
The top bar sticks to the top of the window as the page scrolls. From left to right it holds:
| Part | Class | What it does |
|---|---|---|
| Menu button | .burger #burger | Opens the sidebar. Shown only below 992px. |
| Announcement | .tb-announce | One line of news with a link. Long text ends with "…". Hidden below 992px; delete it if you don't need it. |
| Language | .tb-lang .lang-menu | A dropdown of languages with two-letter codes. |
| Notifications | .tb-btn .notif-menu | A bell with a dot (.badge-dot) and a dropdown of recent items. |
| Profile | .tb-profile .profile-menu | Avatar, name and role, with account links and Sign out. The name hides below 576px. |
The three menus on the right sit in .tb-actions and are ordinary Bootstrap dropdowns (data-bs-toggle="dropdown"), so they need no extra JavaScript.
<li>
<a class="notif-row" href="#">
<div class="notif-ico success"><i class="fas fa-user-plus"></i></div> <!-- or .warn, or no modifier -->
<div class="notif-body">
<div class="notif-title">New subscriber</div>
<div class="notif-text">Lukas joined the mailing list</div>
<div class="notif-time">22 min ago</div>
</div>
</a>
</li>
The language menu is markup only. To switch languages, point each item's href at your back end's language route, and mark the current language with active on its item and its code in the button.
Content and page header
.content holds the page itself. Start it with a .page-header: the title and a short line under it on the left, and optional buttons on the right in a .btn-row. On narrow screens the buttons wrap under the title.
<div class="page-header">
<div>
<h1 class="page-title">Calendar</h1>
<p class="page-sub">Tasks by date.</p>
</div>
<div class="btn-row">
<a href="task-management.html" class="btn-soft"><i class="fas fa-columns"></i> Task Board</a>
<button type="button" class="btn-brand"><i class="fas fa-plus"></i> Add Task</button>
</div>
</div>
To show a breadcrumb above the title, put a <nav aria-label="breadcrumb"> with an <ol class="breadcrumb"> inside the title block, before the .page-title; the header leaves the right space under it. breadcrumbs.html has an example. Below the header, lay the page out with Bootstrap's grid — most pages use <div class="row g-4"> with cards in the columns.
Footer
<footer class="footerbar">
<div class="fb-left">
<span>© 2026 ODIN ADMIN</span>
</div>
<div class="fb-right">
<a href="#" class="fb-link fb-hide-sm">Privacy</a>
<a href="#" class="fb-link fb-hide-sm">Terms</a>
<a href="#" class="fb-link">Support</a>
<span class="fb-brand"><span class="fb-logo" aria-hidden="true"></span> ODIN ADMIN</span>
</div>
</footer>
Links with .fb-hide-sm hide below 576px to save space. .fb-logo draws the logo in the primary colour; remove that span, or the whole .fb-brand, if you don't want it.
Small screens
The layout has two breakpoints, the same as Bootstrap's lg and sm:
| Screen width | What changes |
|---|---|
| 992px and up | The sidebar is always visible and the content sits beside it. |
| Below 992px | The sidebar slides off-screen and the menu button appears in the top bar. The announcement hides and the content padding gets smaller. |
| Below 576px | The name next to the profile avatar hides, and so do footer links with .fb-hide-sm. |
On small screens, the menu button opens the sidebar over the page and dims the rest with the backdrop. It closes when you tap the backdrop, press Esc, pick a link (but not a submenu toggle) or widen the window past 992px. The page doesn't scroll while the menu is open.
The sidebar fires events on #sidebar you can listen to:
document.getElementById('sidebar').addEventListener('odin:sidebar-open', () => {
// e.g. close a search panel
});
// also: 'odin:sidebar-close'
To open or close it from your own code, get the component: Odin.get(document.getElementById('sidebar'), 'sidebar').open() (or .close()).
Sizes
The main sizes are CSS variables in css/base/variables.css. Change them there and every part of the layout follows:
| Variable | Default | Used for |
|---|---|---|
--sidebar-w | 268px | Sidebar width, and the space the content leaves for it |
--topbar-h | 72px | Top bar height, and the logo area at the top of the sidebar |
--footerbar-h | 56px | Footer height |
:root {
--sidebar-w: 240px; /* a narrower sidebar */
}
Colours of the sidebar and the rest of the template are covered on the Theming page.