Skip to content

Commit 780473d

Browse files
knyghtyfelixxm
authored andcommitted
Refs #31034 -- Improved accessibility of admin navigation sidebar.
1 parent 42de52a commit 780473d

File tree

4 files changed

+32
-1
lines changed

4 files changed

+32
-1
lines changed

django/contrib/admin/static/admin/css/nav_sidebar.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
cursor: pointer;
1818
font-size: 20px;
1919
color: #447e9b;
20+
padding: 0;
2021
}
2122

2223
[dir="rtl"] .toggle-nav-sidebar {

django/contrib/admin/static/admin/js/nav_sidebar.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,35 @@
22
{
33
const toggleNavSidebar = document.getElementById('toggle-nav-sidebar');
44
if (toggleNavSidebar !== null) {
5+
const navLinks = document.querySelectorAll('#nav-sidebar a');
6+
function disableNavLinkTabbing() {
7+
for (const navLink of navLinks) {
8+
navLink.tabIndex = -1;
9+
}
10+
}
11+
function enableNavLinkTabbing() {
12+
for (const navLink of navLinks) {
13+
navLink.tabIndex = 0;
14+
}
15+
}
16+
517
const main = document.getElementById('main');
618
let navSidebarIsOpen = localStorage.getItem('django.admin.navSidebarIsOpen');
719
if (navSidebarIsOpen === null) {
820
navSidebarIsOpen = 'true';
921
}
22+
if (navSidebarIsOpen === 'false') {
23+
disableNavLinkTabbing();
24+
}
1025
main.classList.toggle('shifted', navSidebarIsOpen === 'true');
1126

1227
toggleNavSidebar.addEventListener('click', function() {
1328
if (navSidebarIsOpen === 'true') {
1429
navSidebarIsOpen = 'false';
30+
disableNavLinkTabbing();
1531
} else {
1632
navSidebarIsOpen = 'true';
33+
enableNavLinkTabbing();
1734
}
1835
localStorage.setItem('django.admin.navSidebarIsOpen', navSidebarIsOpen);
1936
main.classList.toggle('shifted');
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
<div class="sticky toggle-nav-sidebar" id="toggle-nav-sidebar"></div>
1+
{% load i18n %}
2+
<button class="sticky toggle-nav-sidebar" id="toggle-nav-sidebar" aria-label="{% translate 'Toggle navigation' %}"></button>
23
<nav class="sticky" id="nav-sidebar">
34
{% include 'admin/app_list.html' with app_list=available_apps %}
45
</nav>

tests/admin_views/test_nav_sidebar.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,14 @@ def test_sidebar_starts_open(self):
9797
def test_sidebar_can_be_closed(self):
9898
self.selenium.get(self.live_server_url + reverse('test_with_sidebar:auth_user_changelist'))
9999
toggle_button = self.selenium.find_element_by_css_selector('#toggle-nav-sidebar')
100+
self.assertEqual(toggle_button.tag_name, 'button')
101+
self.assertEqual(toggle_button.get_attribute('aria-label'), 'Toggle navigation')
102+
for link in self.selenium.find_elements_by_css_selector('#nav-sidebar a'):
103+
self.assertEqual(link.get_attribute('tabIndex'), '0')
100104
toggle_button.click()
105+
# Hidden sidebar is not reachable via keyboard navigation.
106+
for link in self.selenium.find_elements_by_css_selector('#nav-sidebar a'):
107+
self.assertEqual(link.get_attribute('tabIndex'), '-1')
101108
main_element = self.selenium.find_element_by_css_selector('#main')
102109
self.assertNotIn('shifted', main_element.get_attribute('class').split())
103110

@@ -115,7 +122,12 @@ def test_sidebar_state_persists(self):
115122
self.assertNotIn('shifted', main_element.get_attribute('class').split())
116123

117124
toggle_button = self.selenium.find_element_by_css_selector('#toggle-nav-sidebar')
125+
# Hidden sidebar is not reachable via keyboard navigation.
126+
for link in self.selenium.find_elements_by_css_selector('#nav-sidebar a'):
127+
self.assertEqual(link.get_attribute('tabIndex'), '-1')
118128
toggle_button.click()
129+
for link in self.selenium.find_elements_by_css_selector('#nav-sidebar a'):
130+
self.assertEqual(link.get_attribute('tabIndex'), '0')
119131
self.assertEqual(
120132
self.selenium.execute_script("return localStorage.getItem('django.admin.navSidebarIsOpen')"),
121133
'true',

0 commit comments

Comments
 (0)