بنقرة واحدة
keyboard-navigation
Implement focus management, optimize tab order, and validate keyboard shortcuts
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Implement focus management, optimize tab order, and validate keyboard shortcuts
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
| name | Keyboard Navigation |
| description | Implement focus management, optimize tab order, and validate keyboard shortcuts |
| category | accessibility |
| required_tools | ["Read","Bash"] |
Ensure all functionality is accessible via keyboard for users who cannot or do not use a mouse, including those with motor disabilities and power users.
Enable Keyboard Access
Implement Standard Keys
Provide Visible Focus Indicators
Manage Focus
Test Keyboard Navigation
Context: Accessible modal dialog with focus trap
class AccessibleModal {
constructor(modalElement) {
this.modal = modalElement;
this.focusableElements = null;
this.firstFocusable = null;
this.lastFocusable = null;
this.previousFocus = null;
// Bind event handlers
this.handleKeyDown = this.handleKeyDown.bind(this);
}
open() {
// Store current focus to restore later
this.previousFocus = document.activeElement;
// Show modal
this.modal.style.display = 'block';
this.modal.setAttribute('aria-hidden', 'false');
// Get all focusable elements
this.focusableElements = this.modal.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
this.firstFocusable = this.focusableElements[0];
this.lastFocusable = this.focusableElements[this.focusableElements.length - 1];
// Focus first element or modal itself
if (this.firstFocusable) {
this.firstFocusable.focus();
} else {
this.modal.focus();
}
// Trap focus
this.modal.addEventListener('keydown', this.handleKeyDown);
// Prevent body scroll
document.body.style.overflow = 'hidden';
}
close() {
// Hide modal
this.modal.style.display = 'none';
this.modal.setAttribute('aria-hidden', 'true');
// Remove event listener
this.modal.removeEventListener('keydown', this.handleKeyDown);
// Restore focus to previous element
if (this.previousFocus) {
this.previousFocus.focus();
}
// Restore body scroll
document.body.style.overflow = '';
}
handleKeyDown(e) {
// Trap focus within modal
if (e.key === 'Tab') {
if (e.shiftKey) {
// Shift+Tab: backward
if (document.activeElement === this.firstFocusable) {
e.preventDefault();
this.lastFocusable.focus();
}
} else {
// Tab: forward
if (document.activeElement === this.lastFocusable) {
e.preventDefault();
this.firstFocusable.focus();
}
}
}
// Close on Escape
if (e.key === 'Escape') {
this.close();
}
}
}
// Usage
const modal = new AccessibleModal(document.getElementById('myModal'));
document.getElementById('openModal').addEventListener('click', () => {
modal.open();
});
document.getElementById('closeModal').addEventListener('click', () => {
modal.close();
});
HTML for Accessible Modal:
<!-- Modal trigger -->
<button
id="openModal"
aria-haspopup="dialog"
aria-expanded="false"
>
Open Dialog
</button>
<!-- Modal -->
<div
id="myModal"
role="dialog"
aria-modal="true"
aria-labelledby="modal-title"
aria-describedby="modal-description"
aria-hidden="true"
tabindex="-1"
>
<div class="modal-content">
<h2 id="modal-title">Confirm Action</h2>
<p id="modal-description">
Are you sure you want to delete this item?
</p>
<div class="modal-actions">
<button id="confirmButton">
Confirm
</button>
<button id="closeModal">
Cancel
</button>
</div>
</div>
</div>
<style>
/* Visible focus indicators */
button:focus,
a:focus,
input:focus {
outline: 3px solid #0066cc;
outline-offset: 2px;
}
/* Focus within modal */
.modal-content *:focus {
outline-color: #0066cc;
}
</style>
Accessible Dropdown Menu:
class AccessibleDropdown {
constructor(button, menu) {
this.button = button;
this.menu = menu;
this.menuItems = menu.querySelectorAll('[role="menuitem"]');
this.currentIndex = -1;
this.button.addEventListener('click', () => this.toggle());
this.button.addEventListener('keydown', (e) => this.handleButtonKey(e));
this.menu.addEventListener('keydown', (e) => this.handleMenuKey(e));
// Close on outside click
document.addEventListener('click', (e) => {
if (!this.button.contains(e.target) && !this.menu.contains(e.target)) {
this.close();
}
});
}
toggle() {
if (this.menu.style.display === 'block') {
this.close();
} else {
this.open();
}
}
open() {
this.menu.style.display = 'block';
this.button.setAttribute('aria-expanded', 'true');
this.currentIndex = 0;
this.menuItems[0].focus();
}
close() {
this.menu.style.display = 'none';
this.button.setAttribute('aria-expanded', 'false');
this.button.focus();
this.currentIndex = -1;
}
handleButtonKey(e) {
// Open on Enter, Space, or Down Arrow
if (e.key === 'Enter' || e.key === ' ' || e.key === 'ArrowDown') {
e.preventDefault();
this.open();
}
}
handleMenuKey(e) {
switch (e.key) {
case 'ArrowDown':
e.preventDefault();
this.currentIndex = (this.currentIndex + 1) % this.menuItems.length;
this.menuItems[this.currentIndex].focus();
break;
case 'ArrowUp':
e.preventDefault();
this.currentIndex = this.currentIndex - 1;
if (this.currentIndex < 0) {
this.currentIndex = this.menuItems.length - 1;
}
this.menuItems[this.currentIndex].focus();
break;
case 'Home':
e.preventDefault();
this.currentIndex = 0;
this.menuItems[0].focus();
break;
case 'End':
e.preventDefault();
this.currentIndex = this.menuItems.length - 1;
this.menuItems[this.currentIndex].focus();
break;
case 'Escape':
e.preventDefault();
this.close();
break;
case 'Enter':
case ' ':
e.preventDefault();
this.menuItems[this.currentIndex].click();
this.close();
break;
}
}
}
Skip Navigation Link:
<!-- Skip link (first focusable element) -->
<a href="#main-content" class="skip-link">
Skip to main content
</a>
<!-- Navigation -->
<nav>
<!-- Many navigation links -->
</nav>
<!-- Main content -->
<main id="main-content" tabindex="-1">
<!-- Page content -->
</main>
<style>
/* Hidden by default, visible on focus */
.skip-link {
position: absolute;
top: -40px;
left: 0;
background: #000;
color: #fff;
padding: 8px;
text-decoration: none;
z-index: 100;
}
.skip-link:focus {
top: 0;
}
</style>
Keyboard Shortcuts:
// Global keyboard shortcuts
document.addEventListener('keydown', (e) => {
// Ignore if typing in input
if (e.target.matches('input, textarea')) {
return;
}
// Ctrl/Cmd + K: Search
if ((e.ctrlKey || e.metaKey) && e.key === 'k') {
e.preventDefault();
document.getElementById('search-input').focus();
}
// ? : Show keyboard shortcuts
if (e.key === '?') {
e.preventDefault();
showKeyboardShortcuts();
}
// Esc: Close any open modals
if (e.key === 'Escape') {
closeAllModals();
}
});
// Show keyboard shortcuts dialog
function showKeyboardShortcuts() {
const shortcuts = [
{ keys: 'Ctrl+K', action: 'Open search' },
{ keys: '?', action: 'Show keyboard shortcuts' },
{ keys: 'Esc', action: 'Close dialog' },
{ keys: 'Tab', action: 'Next element' },
{ keys: 'Shift+Tab', action: 'Previous element' },
];
// Display shortcuts in accessible modal
showModal({
title: 'Keyboard Shortcuts',
content: renderShortcuts(shortcuts)
});
}
Testing Keyboard Navigation:
## Testing Checklist
### Basic Navigation
- [ ] Tab moves forward through all interactive elements
- [ ] Shift+Tab moves backward
- [ ] Focus indicator always visible
- [ ] Tab order is logical (reading order)
- [ ] No keyboard traps (can escape every control)
### Interactive Elements
- [ ] Enter activates buttons and links
- [ ] Space activates buttons and checkboxes
- [ ] Arrow keys navigate dropdowns/menus
- [ ] Escape closes modals and menus
- [ ] Custom controls have keyboard support
### Forms
- [ ] Tab moves between form fields
- [ ] Arrow keys work in radio groups
- [ ] Space toggles checkboxes
- [ ] Enter submits form
- [ ] Error messages reachable via keyboard
### Modals
- [ ] Focus moves to modal when opened
- [ ] Tab cycles within modal (focus trap)
- [ ] Escape closes modal
- [ ] Focus returns to trigger on close
### Navigation
- [ ] Skip link works
- [ ] All navigation items reachable
- [ ] Current page indicated
- [ ] Submenus keyboard accessible
### Custom Controls
- [ ] Appropriate ARIA roles
- [ ] Keyboard interactions documented
- [ ] All states keyboard accessible
- [ ] Focus management correct
Design AI agents with appropriate capabilities, tools, and personas for specific software development tasks
Design RESTful APIs with proper resource modeling, HTTP methods, error handling, and clear contracts following REST principles
Document APIs comprehensively with signatures, parameters, return values, errors, and working code examples for developer reference
Implement robust third-party API integrations with proper authentication, error handling, and rate limiting
Apply proven architectural patterns (MVC, layered, microservices) to create maintainable systems with clear separation of concerns
Systematically reproduce, diagnose, and analyze bugs to determine root cause, assess severity, and plan fix strategy