qave
v1.0.0
Published
Quantum Accessible Virtualized Environment - Focus Management & Decision Governance
Maintainers
Readme
QAVE Lite 🎯
Quick Accessibility & Voice Experience - Lite Edition
A lightweight, high-performance focus management library for building accessible web applications. QAVE Lite provides essential keyboard navigation and focus control with zero dependencies.
✨ Features
- 🎯 Zero Dependencies - Pure TypeScript, no external libs
- ⚡ High Performance - Handles 10,000+ nodes efficiently
- 🎹 Keyboard Navigation - Tab, Shift+Tab, Home, End support
- 🔒 Focus Traps - Modal and dialog focus management
- 📦 Tree-Shakeable - ESM, CJS, and UMD builds
- 🧪 Well Tested - 66 tests, 90% coverage
- 💪 TypeScript - Full type safety
- 📦 Tiny Bundle - ~3KB minified + gzipped
📦 Installation
npm install qave-lite
Or with yarn:
yarn add qave-lite
Or with pnpm:
pnpm add qave-lite
🚀 Quick Start
import { QAVELite } from 'qave-lite';
// Create instance
const qave = new QAVELite();
// Register focusable elements
qave.register({ id: 'button-1', focusable: true, tabIndex: 1 });
qave.register({ id: 'button-2', focusable: true, tabIndex: 2 });
qave.register({ id: 'button-3', focusable: true, tabIndex: 3 });
// Navigate
qave.apply('next'); // Move to next element
qave.apply('previous'); // Move to previous element
qave.apply('first'); // Jump to first element
qave.apply('last'); // Jump to last element
// Get current state
const state = qave.getState();
console.log(state.activeId); // Current focused element ID
// Unregister when done
qave.unregister('button-1');
📖 API Reference
QAVELite
Main class for focus management.
Methods
register(node: QAVENode): void
Register a focusable element.
qave.register({
id: 'my-button', // Required: Unique identifier
focusable: true, // Required: Whether element can receive focus
tabIndex: 1, // Optional: Tab order
disabled: false, // Optional: Is element disabled?
group: 'modal' // Optional: Group for focus traps
});
unregister(id: string): void
Remove an element from focus management.
qave.unregister('my-button');
apply(action: NavigationAction): string | null
Perform a navigation action. Returns the ID of the newly focused element, or null if no element was found.
type NavigationAction = 'next' | 'previous' | 'first' | 'last';
const focusedId = qave.apply('next');
getState(): QAVEState
Get the current focus state.
const state = qave.getState();
interface QAVEState {
activeId: string | null; // Currently focused element
previousId: string | null; // Previously focused element
history: string[]; // Focus history (max 3)
}
🎯 Usage Examples
Basic Navigation
import { QAVELite } from 'qave-lite';
const qave = new QAVELite();
// Register buttons
['btn-1', 'btn-2', 'btn-3'].forEach((id, index) => {
qave.register({ id, focusable: true, tabIndex: index + 1 });
});
// Tab navigation
document.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
e.preventDefault();
const action = e.shiftKey ? 'previous' : 'next';
const focusedId = qave.apply(action);
if (focusedId) {
document.getElementById(focusedId)?.focus();
}
}
});
Modal Focus Trap
const qave = new QAVELite();
// Register page elements
qave.register({ id: 'page-btn-1', focusable: true, tabIndex: 1 });
qave.register({ id: 'page-btn-2', focusable: true, tabIndex: 2 });
// Open modal - register modal elements
function openModal() {
qave.register({ id: 'modal-btn-1', focusable: true, tabIndex: 10, group: 'modal' });
qave.register({ id: 'modal-btn-2', focusable: true, tabIndex: 11, group: 'modal' });
qave.register({ id: 'modal-close', focusable: true, tabIndex: 12, group: 'modal' });
// Focus first modal element
qave.apply('next');
}
// Close modal - unregister modal elements
function closeModal() {
qave.unregister('modal-btn-1');
qave.unregister('modal-btn-2');
qave.unregister('modal-close');
// Focus returns to page automatically via history
}
Disabled Elements
qave.register({
id: 'submit-btn',
focusable: true,
tabIndex: 1,
disabled: true // Will be skipped during navigation
});
// Enable later
qave.register({
id: 'submit-btn',
focusable: true,
tabIndex: 1,
disabled: false
});
⚡ Performance
QAVE Lite is optimized for performance:
1,000 nodes: ~6ms registration
5,000 nodes: ~7ms registration
10,000 nodes: ~11ms registration
100 navigations: ~12ms
Memory: Constant O(1) history size
Benchmarked on modern browsers (Chrome, Firefox, Safari).
🌐 Browser Support
✅ Chrome 90+
✅ Firefox 88+
✅ Safari 14+
✅ Edge 90+
📦 Bundle Sizes
Format
Size (minified)
Size (gzipped)
ESM
~8KB
~3KB
CJS
~8KB
~3KB
UMD
~9KB
~3.5KB
🧪 Testing
# Run all tests
npm test
# Run specific test file
npm test tests/1-basic.test.ts
# Run with coverage
npm test -- --coverage
# Watch mode
npm test -- --watch
Current test coverage: 90% statements, 81% branches, 93% functions
🛠️ Development
# Install dependencies
npm install
# Build
npm run build
# Test
npm test
# Watch mode
npm run build -- --watch
📄 License
MIT © ESQT
🤝 Contributing
Contributions welcome! See CONTRIBUTING.md for guidelines.
🔗 Links
Full QAVE Library
Documentation
Examples
💡 Migration from Full QAVE
See MIGRATION.md for migration guide from the full QAVE library.
Made with ❤️ by ESQT