This document describes how React Aria usage is enforced as a coding standard in this project.
To prevent the hover state issues we experienced (where onMouseLeave doesn't fire reliably), we've implemented automated enforcement of React Aria hooks over raw DOM events.
The following DOM event handlers are prohibited via ESLint:
onMouseEnter→ UseuseHoverfrom@react-aria/interactionsonMouseLeave→ UseuseHoverfrom@react-aria/interactionsonMouseOver→ UseuseHoverfrom@react-aria/interactionsonMouseOut→ UseuseHoverfrom@react-aria/interactions
Custom ESLint rules using no-restricted-syntax to detect and block mouse event handlers:
'no-restricted-syntax': [
'error',
{
selector: 'JSXAttribute[name.name="onMouseEnter"]',
message: 'Avoid using onMouseEnter. Use React Aria\'s useHover hook...'
},
// ... similar rules for onMouseLeave, onMouseOver, onMouseOut
]We also enforce accessibility best practices via eslint-plugin-jsx-a11y:
jsx-a11y/mouse-events-have-key-events- Ensures keyboard equivalentsjsx-a11y/no-static-element-interactions- Warns about interactive non-semantic elements
npm run lint # Check for violations
npm run lint:fix # Auto-fix where possible# Check for violations
npm run lint
# Auto-fix issues
npm run lint:fixAdd to your CI pipeline:
- name: Lint
run: |
cd frontend
npm run lintYou can add a pre-commit hook using husky:
npm install --save-dev husky lint-staged
npx husky initAdd to .husky/pre-commit:
cd frontend && npm run lintWhen ESLint detects a mouse event violation, you'll see:
error Avoid using onMouseEnter. Use React Aria's useHover hook from
@react-aria/interactions for robust, accessible hover interactions
❌ Before (Prohibited):
<div
onMouseEnter={() => setHover(true)}
onMouseLeave={() => setHover(false)}
>
Content
</div>✅ After (Enforced):
import { useHover } from '@react-aria/interactions';
function Component() {
const { hoverProps, isHovered } = useHover({});
return <div {...hoverProps}>Content</div>;
}In rare cases where React Aria cannot be used, you can disable the rule:
{/* eslint-disable-next-line no-restricted-syntax */}
<div onMouseEnter={handler}>
{/* Justification: Legacy library integration requires raw events */}
</div>Important: Exemptions require:
- Code review approval
- Clear justification in comments
- Comprehensive testing for edge cases
React Aria's useHover solves critical issues that raw mouse events have:
- Reliability: Handles fast mouse movements and window blur
- Accessibility: Supports keyboard navigation and screen readers
- Cross-platform: Works correctly on touch devices
- Browser consistency: Normalizes behavior across browsers
See the React Aria Documentation for more details.
- CODING_STANDARDS.md - Full coding standards
- React Aria useHover
- eslint-plugin-jsx-a11y
To add more restricted events, edit eslint.config.js:
{
selector: 'JSXAttribute[name.name="onFocus"]',
message: 'Use React Aria\'s useFocus hook instead'
}To see all current violations in the codebase:
npm run lintThis will show files that need updating to comply with standards.