(null);
const languages = [
@@ -30,8 +31,28 @@ const LanguageSwitcher = () => {
};
const handleKeyDown = (e: React.KeyboardEvent) => {
- if (e.key === 'Escape') {
- setIsOpen(false);
+ if (!isOpen) return;
+
+ switch (e.key) {
+ case 'Escape':
+ setIsOpen(false);
+ setFocusedIndex(-1);
+ break;
+ case 'ArrowDown':
+ e.preventDefault();
+ setFocusedIndex(prev => (prev + 1) % languages.length);
+ break;
+ case 'ArrowUp':
+ e.preventDefault();
+ setFocusedIndex(prev => (prev - 1 + languages.length) % languages.length);
+ break;
+ case 'Enter':
+ e.preventDefault();
+ if (focusedIndex >= 0) {
+ handleLanguageChange(languages[focusedIndex].code);
+ setFocusedIndex(-1);
+ }
+ break;
}
};
@@ -63,7 +84,10 @@ const LanguageSwitcher = () => {
px-4 py-2 rounded-full transition-all duration-200
hover:bg-zinc-800/50 border border-transparent hover:border-zinc-800
hover:scale-105 active:scale-95"
- onClick={() => setIsOpen(!isOpen)}
+ onClick={() => {
+ setIsOpen(!isOpen);
+ setFocusedIndex(-1);
+ }}
aria-expanded={isOpen}
aria-haspopup="listbox"
aria-label="Select language"
@@ -79,18 +103,21 @@ const LanguageSwitcher = () => {
${isOpen ? 'opacity-100 scale-100' : 'opacity-0 scale-95 pointer-events-none'}`}
role="listbox"
aria-label="Languages"
+ aria-activedescendant={focusedIndex >= 0 ? `lang-option-${languages[focusedIndex].code}` : undefined}
onKeyDown={handleKeyDown}
>
- {languages.map((lang) => (
+ {languages.map((lang, index) => (