Các sự kiện Focus chính
| Sự kiện | Kích hoạt khi | Bubbles |
|---|---|---|
| focus | Element nhận focus | ❌ Không |
| blur | Element mất focus | ❌ Không |
| focusin | Element sắp nhận focus | ✅ Có |
| focusout | Element sắp mất focus | ✅ Có |
Lưu ý: focus/blur không bubble, nhưng focusin/focusout bubble. Dùng focusin/focusout khi cần delegate event.
Ví dụ: Đổi màu nền khi focus
<!DOCTYPE html>
<html lang="vi">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Focus Events</title>
<style>
body { font-family: 'Segoe UI', sans-serif; padding: 20px; }
input { display: block; margin: 10px 0; padding: 12px; width: 300px; border: 2px solid #ddd; border-radius: 6px; font-size: 16px; transition: all 0.2s; }
input:focus { border-color: #1976d2; box-shadow: 0 0 0 3px rgba(25,118,210,0.1); outline: none; }
.hint { color: #666; font-size: 14px; }
</style>
</head>
<body>
<h1>Focus Events trong JavaScript</h1>
<form id="form">
<input type="text" placeholder="Username" autocomplete="username">
<input type="password" class="passW" placeholder="Password" autocomplete="current-password">
</form>
<p class="hint">Focus vào ô Password để thấy background đổi màu xanh nhạt</p>
<script>
const passEle = document.querySelector('.passW');
// focus: không bubble - gắn trực tiếp trên element
passEle.addEventListener('focus', () => {
passEle.style.backgroundColor = '#e8f5e9'; // Xanh nhạt
});
// blur: khi mất focus
passEle.addEventListener('blur', () => {
passEle.style.backgroundColor = ''; // Reset về mặc định
});
// Demo focusin/focusout (bubble) - gắn trên form cha
document.getElementById('form').addEventListener('focusin', (e) => {
console.log('focusin:', e.target.tagName, e.target.type);
});
document.getElementById('form').addEventListener('focusout', (e) => {
console.log('focusout:', e.target.tagName);
});
</script>
</body>
</html>
Kết quả
Khi click vào ô Password: background chuyển sang xanh nhạt.
Khi click ra ngoài: background trở về trắng.
Ứng dụng thực tế
1. Validation khi blur (mất focus)
emailInput.addEventListener('blur', () => {
if (emailInput.value && !emailInput.validity.valid) {
showError(emailInput, 'Email không hợp lệ');
}
});
2. Floating Label Pattern
input.addEventListener('focus', () => label.classList.add('active'));
input.addEventListener('blur', () => {
if (!input.value) label.classList.remove('active');
});
3. Trap Focus trong Modal (Accessibility)
function trapFocus(modal) {
const focusable = modal.querySelectorAll('button, input, select, textarea, a[href], [tabindex]:not([tabindex="-1"])');
const first = focusable[0];
const last = focusable[focusable.length - 1];
modal.addEventListener('keydown', (e) => {
if (e.key !== 'Tab') return;
if (e.shiftKey && document.activeElement === first) {
e.preventDefault(); last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault(); first.focus();
}
});
first.focus(); // Auto-focus khi mở
}
4. document.activeElement
// Kiểm tra element nào đang focus
console.log(document.activeElement);
// Kiểm tra có element nào focus không
if (document.activeElement === document.body) {
console.log('Không có element nào focus');
}