sidebar
Use ng-sidebar on an aside inside .sidebar-layout and connect native
button triggers with aria-controls. Author physical side, visual variant, and
collapse mode directly on the sidebar root.
<div>
<aside id="app-sidebar" ng-sidebar side="left" collapsible="icon">
<header>
<a href="/">Acme Inc.</a>
</header>
<nav>
<section>
<h3>Workspace</h3>
<div>
<ul>
<li>
<a aria-current="page" href="/dashboard"> Dashboard </a>
</li>
</ul>
</div>
</section>
</nav>
</aside>
<main>
<button aria-controls="app-sidebar">Toggle sidebar</button>
</main>
</div>
The directive reads root options and coordinates collapse, group relationships,
and trigger accessibility state. AngularTS may control the boolean collapsed
attribute; it continues to own filtering, shortcuts, routing, and actions.
Compose nested disclosure with native details.disclosure and action menus
with ng-dropdown-menu. Add responsive to an off-canvas sidebar to initialize
it collapsed below 48rem and expanded at larger viewport widths.
Example
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Sidebar</title>
<link rel="stylesheet" href="../../css/preflight.css" />
<link rel="stylesheet" href="../../css/angular.css" />
<link rel="stylesheet" href="../example.css" />
<script src="../../js/angular-ts.umd.js"></script>
<script src="../../js/angular-css.umd.js"></script>
</head>
<body
ng-app="angular.css"
ng-cloak
ng-init="sidebarOpen=true; sidebarQuery=''"
ng-keydown="($event.ctrlKey || $event.metaKey) && $event.key === 'b' && (sidebarOpen = !sidebarOpen)"
data-example="sidebar-demo sidebar-controlled"
>
<div class="visual-example">
<aside
id="app-sidebar"
ng-sidebar
collapsible="icon"
ng-attr-collapsed="{{ sidebarOpen ? undefined : '' }}"
class="sidebar-demo-panel"
aria-label="Workspace navigation"
>
<header>
<a href="#workspace" size="lg">
<span class="sidebar-brand-mark" aria-hidden="true">A</span>
<span class="sidebar-brand-copy">
<strong>Acme Inc</strong>
<small>Enterprise</small>
</span>
</a>
<input
ng-model="sidebarQuery"
aria-label="Filter navigation"
placeholder="Filter projects..."
/>
</header>
<hr />
<nav>
<section>
<h3>Platform</h3>
<ul>
<li>
<a href="#playground" aria-current="page">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<rect x="4" y="4" width="16" height="16" rx="2"></rect>
<path d="m8 9 2 2-2 2M13 15h3"></path>
</svg>
<span>Playground</span>
</a>
<ul>
<li>
<a href="#history">History</a>
</li>
<li>
<a href="#starred">Starred</a>
</li>
<li>
<a href="#settings">Settings</a>
</li>
</ul>
</li>
<li>
<a href="#models">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<circle cx="12" cy="8" r="3"></circle>
<path d="M5 20c1-4 3.5-6 7-6s6 2 7 6"></path>
</svg>
<span>Models</span>
</a>
</li>
<li>
<a href="#documentation">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path
d="M4 5.5A2.5 2.5 0 0 1 6.5 3H11v17H6.5A2.5 2.5 0 0 0 4 22zM20 5.5A2.5 2.5 0 0 0 17.5 3H13v17h4.5A2.5 2.5 0 0 1 20 22z"
></path>
</svg>
<span>Documentation</span>
</a>
</li>
</ul>
</section>
<section>
<h3>Projects</h3>
<ul>
<li>
<a href="#design">
<span class="sidebar-menu-dot" aria-hidden="true"></span>
<span>Design Engineering</span>
</a>
<output>24</output>
</li>
<li>
<a href="#sales">
<span class="sidebar-menu-dot" aria-hidden="true"></span>
<span>Sales & Marketing</span>
</a>
<output>12</output>
</li>
<li>
<a href="#travel">
<span class="sidebar-menu-dot" aria-hidden="true"></span>
<span>Travel</span>
</a>
<output>3</output>
</li>
</ul>
</section>
</nav>
<footer>
<button size="lg">
<span class="avatar"><span>JD</span></span>
<span class="sidebar-brand-copy">
<strong>Jane Doe</strong>
<small>jane@example.com</small>
</span>
</button>
</footer>
</aside>
<main class="sidebar-demo-inset">
<header class="sidebar-demo-toolbar">
<button
variant="ghost"
size="sm"
aria-controls="app-sidebar"
aria-keyshortcuts="Control+B Meta+B"
ng-click="sidebarOpen=!sidebarOpen"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<rect x="3" y="4" width="18" height="16" rx="2"></rect>
<path d="M9 4v16"></path>
</svg>
<span
ng-bind="sidebarOpen ? 'Close Sidebar' : 'Open Sidebar'"
></span>
</button>
</header>
<section class="sidebar-dashboard">
<div>
<span class="sidebar-dashboard-kicker">Overview</span>
<h1>Dashboard</h1>
<p>Monitor your team activity and active projects.</p>
</div>
<div class="sidebar-metric-grid">
<article><span>Active projects</span><strong>24</strong></article>
<article><span>Team members</span><strong>18</strong></article>
<article><span>Completion</span><strong>86%</strong></article>
</div>
<output class="sidebar-query-output" aria-live="polite">
Filter: <span ng-bind="sidebarQuery || 'All projects'"></span>
</output>
</section>
</main>
</div>
</body>
</html>
Anatomy
Header and footer menus, labeled groups, actions, badges, submenus, and loading rows remain independently composable.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Sidebar Anatomy</title>
<link rel="stylesheet" href="../../css/preflight.css" />
<link rel="stylesheet" href="../../css/angular.css" />
<link rel="stylesheet" href="../example.css" />
<script src="../../js/angular-ts.umd.js"></script>
<script src="../../js/angular-css.umd.js"></script>
</head>
<body
ng-app="angular.css"
ng-cloak
ng-init="sidebarAction='None'; projectsLoading=true"
data-example="sidebar-footer sidebar-group sidebar-group-action sidebar-header sidebar-menu sidebar-menu-action sidebar-menu-badge sidebar-menu-sub sidebar-rsc"
>
<div class="sidebar-anatomy-shell visual-example">
<aside
id="anatomy-sidebar"
ng-sidebar
collapsible="none"
class="sidebar-anatomy-panel"
>
<header>
<div ng-dropdown-menu>
<button size="lg">
<span class="sidebar-brand-mark" aria-hidden="true">A</span>
<span class="sidebar-brand-copy">
<strong>Select Workspace</strong>
<small>Acme Inc</small>
</span>
</button>
<menu>
<button ng-click="sidebarAction='Workspace: Acme Inc'">
Acme Inc
</button>
<button ng-click="sidebarAction='Workspace: Acme Corp.'">
Acme Corp.
</button>
</menu>
</div>
</header>
<nav>
<section>
<h3>Projects</h3>
<button
aria-label="Add Project"
ng-click="sidebarAction='Added project'"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M12 5v14M5 12h14"></path>
</svg>
</button>
<ul>
<li>
<a href="#design">
<span class="sidebar-menu-dot" aria-hidden="true"></span>
<span>Design Engineering</span>
</a>
<div ng-dropdown-menu>
<button aria-label="More actions for Design Engineering">
<svg
viewBox="0 0 24 24"
fill="currentColor"
aria-hidden="true"
>
<circle cx="5" cy="12" r="1.5"></circle>
<circle cx="12" cy="12" r="1.5"></circle>
<circle cx="19" cy="12" r="1.5"></circle>
</svg>
</button>
<menu side="right" align="start">
<button
ng-click="sidebarAction='Edited Design Engineering'"
>
Edit Project
</button>
<button
ng-click="sidebarAction='Deleted Design Engineering'"
>
Delete Project
</button>
</menu>
</div>
</li>
<li>
<a href="#sales">
<span class="sidebar-menu-dot" aria-hidden="true"></span>
<span>Sales & Marketing</span>
</a>
<output>12</output>
</li>
<li>
<a href="#travel">
<span class="sidebar-menu-dot" aria-hidden="true"></span>
<span>Travel</span>
</a>
<output>3</output>
</li>
</ul>
</section>
<section>
<h3>Documentation</h3>
<ul>
<li>
<a href="#getting-started">Getting Started</a>
<ul>
<li>
<a href="#installation">Installation</a>
</li>
<li>
<a aria-current="page" href="#structure"
>Project Structure</a
>
</li>
</ul>
</li>
</ul>
</section>
<section>
<h3>Remote projects</h3>
<button
aria-label="Toggle loading"
ng-click="projectsLoading=!projectsLoading"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="M20 12a8 8 0 1 1-2.3-5.7M20 4v6h-6"></path>
</svg>
</button>
<ul>
<li
ng-if="projectsLoading"
aria-label="Loading project"
class="skeleton"
></li>
<li
ng-if="projectsLoading"
aria-label="Loading project"
class="skeleton"
></li>
<li
ng-if="projectsLoading"
aria-label="Loading project"
class="skeleton"
></li>
<li ng-if="!projectsLoading">
<a href="#support">Support</a>
</li>
<li ng-if="!projectsLoading">
<a href="#feedback">Feedback</a>
</li>
</ul>
</section>
</nav>
<footer>
<div ng-dropdown-menu>
<button size="lg">
<span class="avatar"><span>UN</span></span>
<span class="sidebar-brand-copy"
><strong>Username</strong><small>Account menu</small></span
>
</button>
<menu side="top">
<button ng-click="sidebarAction='Account'">Account</button>
<button ng-click="sidebarAction='Billing'">Billing</button>
<button ng-click="sidebarAction='Signed out'">Sign out</button>
</menu>
</div>
</footer>
</aside>
<main class="sidebar-anatomy-inset">
<div>
<span class="sidebar-dashboard-kicker">Component anatomy</span>
<h1>Sidebar primitives</h1>
<p>
Header, footer, groups, actions, badges, submenus, and loading
states compose independently.
</p>
</div>
<output
class="sidebar-anatomy-output"
aria-live="polite"
ng-bind="sidebarAction"
></output>
</main>
</div>
</body>
</html>
Disclosure Navigation
This example delegates both group and menu disclosure to the existing Disclosure pattern.
View source
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Sidebar Collapsible</title>
<link rel="stylesheet" href="../../css/preflight.css" />
<link rel="stylesheet" href="../../css/angular.css" />
<link rel="stylesheet" href="../example.css" />
<script src="../../js/angular-ts.umd.js"></script>
<script src="../../js/angular-css.umd.js"></script>
</head>
<body
ng-app="angular.css"
ng-cloak
data-example="sidebar-group-collapsible sidebar-menu-collapsible"
>
<div class="sidebar-collapsible-shell visual-example">
<aside
id="collapsible-sidebar"
ng-sidebar
collapsible="none"
class="sidebar-collapsible-panel"
aria-label="Documentation navigation"
>
<header>
<a href="#docs" size="lg">
<span class="sidebar-brand-mark" aria-hidden="true">D</span>
<span class="sidebar-brand-copy">
<strong>Documentation</strong>
<small>Developer platform</small>
</span>
</a>
</header>
<nav>
<details open class="disclosure">
<summary>
Help
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m6 9 6 6 6-6"></path>
</svg>
</summary>
<div>
<ul>
<li>
<a href="#support">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<circle cx="12" cy="12" r="9"></circle>
<path
d="M8.5 8.5 6 6m9.5 2.5L18 6m-9.5 9.5L6 18m9.5-2.5L18 18"
></path>
</svg>
<span>Support</span>
</a>
</li>
<li>
<a href="#feedback">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m22 2-7 20-4-9-9-4zM22 2 11 13"></path>
</svg>
<span>Feedback</span>
</a>
</li>
</ul>
</div>
</details>
<section>
<h3>Guide</h3>
<ul>
<li>
<details open class="disclosure">
<summary>
<span>Getting Started</span>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6"></path>
</svg>
</summary>
<div>
<ul>
<li>
<a href="#installation">Installation</a>
</li>
<li>
<a aria-current="page" href="#structure"
>Project Structure</a
>
</li>
</ul>
</div>
</details>
</li>
<li>
<details class="disclosure">
<summary>
<span>Build Your Application</span>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6"></path>
</svg>
</summary>
<div>
<ul>
<li>
<a href="#routing">Routing</a>
</li>
<li>
<a href="#data">Data Fetching</a>
</li>
<li>
<a href="#rendering">Rendering</a>
</li>
</ul>
</div>
</details>
</li>
<li>
<details class="disclosure">
<summary>
<span>API Reference</span>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<path d="m9 18 6-6-6-6"></path>
</svg>
</summary>
<div>
<ul>
<li>
<a href="#components">Components</a>
</li>
<li>
<a href="#functions">Functions</a>
</li>
</ul>
</div>
</details>
</li>
</ul>
</section>
</nav>
</aside>
<main class="sidebar-collapsible-inset">
<span class="sidebar-dashboard-kicker">Composition</span>
<h1>Collapsible navigation</h1>
<p>Disclosure behavior is supplied by native details elements.</p>
</main>
</div>
</body>
</html>
RTL
Physical right placement and logical borders, actions, and submenu indentation follow the authored document direction.
View source
<!doctype html>
<html lang="ar" dir="rtl">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>AngularCSS Sidebar Rtl</title>
<link rel="stylesheet" href="../../css/preflight.css" />
<link rel="stylesheet" href="../../css/angular.css" />
<link rel="stylesheet" href="../example.css" />
<script src="../../js/angular-ts.umd.js"></script>
<script src="../../js/angular-css.umd.js"></script>
</head>
<body
ng-app="angular.css"
ng-cloak
ng-init="sidebarOpen=true; sidebarAction='جاهز'"
data-example="sidebar-rtl"
>
<div class="sidebar-rtl-shell visual-example">
<main class="sidebar-rtl-inset">
<header class="sidebar-demo-toolbar">
<button
variant="ghost"
size="sm"
aria-controls="rtl-sidebar"
ng-click="sidebarOpen=!sidebarOpen"
>
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<rect x="3" y="4" width="18" height="16" rx="2"></rect>
<path d="M15 4v16"></path>
</svg>
<span ng-bind="sidebarOpen ? 'إغلاق الشريط' : 'فتح الشريط'"></span>
</button>
</header>
<section class="sidebar-dashboard">
<div>
<span class="sidebar-dashboard-kicker">نظرة عامة</span>
<h1>لوحة التحكم</h1>
<p>تابع نشاط الفريق والمشاريع الحالية.</p>
</div>
<output
class="sidebar-anatomy-output"
aria-live="polite"
ng-bind="sidebarAction"
></output>
</section>
</main>
<aside
id="rtl-sidebar"
ng-sidebar
side="right"
variant="floating"
collapsible="icon"
ng-attr-collapsed="{{ sidebarOpen ? undefined : '' }}"
class="sidebar-rtl-panel"
aria-label="التنقل في مساحة العمل"
>
<header>
<a href="#workspace" size="lg">
<span class="sidebar-brand-mark" aria-hidden="true">أ</span>
<span class="sidebar-brand-copy"
><strong>شركة أكمي</strong><small>المؤسسة</small></span
>
</a>
</header>
<nav>
<section>
<h3>المنصة</h3>
<ul>
<li>
<a aria-current="page" href="#playground">
<svg
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
aria-hidden="true"
>
<rect x="4" y="4" width="16" height="16" rx="2"></rect>
<path d="m8 9 2 2-2 2M13 15h3"></path>
</svg>
<span>ملعب</span>
</a>
<ul>
<li>
<a href="#history">السجل</a>
</li>
<li>
<a href="#starred">المميز</a>
</li>
<li>
<a href="#settings">الإعدادات</a>
</li>
</ul>
</li>
<li>
<a href="#models"
><span class="sidebar-menu-dot" aria-hidden="true"></span
><span>النماذج</span></a
>
</li>
</ul>
</section>
<section>
<h3>المشاريع</h3>
<ul>
<li>
<a href="#design"
><span class="sidebar-menu-dot" aria-hidden="true"></span
><span>هندسة التصميم</span></a
>
<div ng-dropdown-menu>
<button aria-label="المزيد">
<svg
viewBox="0 0 24 24"
fill="currentColor"
aria-hidden="true"
>
<circle cx="5" cy="12" r="1.5"></circle>
<circle cx="12" cy="12" r="1.5"></circle>
<circle cx="19" cy="12" r="1.5"></circle>
</svg>
</button>
<menu side="left" align="start">
<button ng-click="sidebarAction='عرض المشروع'">
عرض المشروع
</button>
<button ng-click="sidebarAction='مشاركة المشروع'">
مشاركة المشروع
</button>
</menu>
</div>
</li>
<li>
<a href="#sales"
><span class="sidebar-menu-dot" aria-hidden="true"></span
><span>المبيعات والتسويق</span></a
>
</li>
<li>
<a href="#travel"
><span class="sidebar-menu-dot" aria-hidden="true"></span
><span>السفر</span></a
>
</li>
</ul>
</section>
</nav>
<footer>
<button size="lg" ng-click="sidebarAction='الحساب'">
<span class="avatar"><span>ش</span></span>
<span class="sidebar-brand-copy"
><strong>أنغولار سي إس إس</strong
><small>team@angularcss.dev</small></span
>
</button>
</footer>
</aside>
</div>
</body>
</html>
Installation
Install AngularCSS, load its stylesheet, and include the angular.css module in your AngularTS application. See Installation for the complete setup.
This component’s root directive is [ng-sidebar]. Importing the package registers it with the AngularCSS angular.css module; there is no per-component JavaScript registration step.
Anatomy
Directive selectors
ng-sidebar
Semantic structure
Place aside[ng-sidebar] beside main and connect native button triggers with aria-controls. The root directive inspects semantic header, nav, section, list, and footer descendants; no child sidebar directives or anatomy classes are required. Author side, variant, and collapse mode on the root. Compose nested disclosure with native details.disclosure and action menus with ng-dropdown-menu.
API
Attributes and state
| Attribute | Access | Purpose |
|---|---|---|
aria-controls | Output | ID of the element controlled by a trigger. |
aria-current | Input | Current item or date state. |
aria-expanded | Output | Open or expanded state exposed to assistive technology. |
aria-hidden | Output | Whether generated or collapsed content is hidden from assistive technology. |
aria-labelledby | Output | ID of the element that supplies the accessible name. |
collapsed | Input/output | Current collapsed state. |
collapsible | Input/output | Collapse behavior: offcanvas, icon, or none. |
inert | Output | Prevents interaction while the component is hidden. |
responsive | Input | Collapses an off-canvas sidebar below 48rem and expands it above that breakpoint. |
role | Input/output | Explicit semantic role when native HTML does not provide one. |
side | Input/output | Physical placement: left or right. |
variant | Input/output | Surface style: sidebar, floating, or inset. |
Input attributes are read from authored HTML. Output attributes are maintained by AngularCSS for CSS and testing. Input/output attributes may be authored for a controlled initial state and are then synchronized by the directive.
CSS custom properties
This directive does not write component-specific CSS custom properties.
DOM events
This component does not emit a component-specific custom event.
Native DOM events continue to work normally. AngularTS event directives such as
ng-click and ng-keydown, plus the data-change model callback, remain application-owned.
Behavior
The directive reflects authored side, variant, collapsible, direction, responsive, active-item, group, and trigger state. It owns only sidebar collapse and accessibility synchronization; collapsible=none stays expanded, off-canvas collapse hides the landmark, and icon collapse keeps visible controls accessible. AngularTS remains responsible for controlled open state, shortcuts, filtering, routing, application actions, and structural rendering. Compose nested disclosure with the Disclosure pattern and action menus with Dropdown Menu.
AngularCSS does not replace AngularTS interpolation, bindings, structural directives, form controllers, validation, or application state.
Accessibility
Give the sidebar landmark and icon-only actions useful accessible names. Triggers expose aria-controls and expanded state, groups are associated with visible labels, and the current destination uses aria-current=page. Off-canvas collapse hides the landmark and restores trigger focus when necessary; icon collapse preserves access to its visible controls. Keep DOM order aligned with physical placement and use native links for destinations.
Authored accessible names and relationships are preserved. Test the final composition with keyboard navigation and assistive technology because labels and content come from the application.
Customization
Target [ng-sidebar], semantic descendants, component classes, and generated state with ordinary CSS. Keep behavior and accessible state in the TypeScript directive; visual choices belong in the application stylesheet.
Read Customization for layer order, design tokens, state variants, and iframe demo isolation.
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.