diff --git a/src/components/OrbitAccountPicker.tsx b/src/components/OrbitAccountPicker.tsx
index f467e547..6358ec2b 100644
--- a/src/components/OrbitAccountPicker.tsx
+++ b/src/components/OrbitAccountPicker.tsx
@@ -1,4 +1,4 @@
-import { useEffect } from 'react';
+import { useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import { X, User } from 'lucide-react';
import { useTranslation } from 'react-i18next';
@@ -13,13 +13,43 @@ import { useOrbitAccountPickerStore } from '../store/orbitAccountPickerStore';
export default function OrbitAccountPicker() {
const { t } = useTranslation();
const { isOpen, accounts, pick, cancel } = useOrbitAccountPickerStore();
+ const [selected, setSelected] = useState(0);
+ const itemRefs = useRef<(HTMLButtonElement | null)[]>([]);
+
+ // Reset + focus first item each time the picker re-opens.
+ useEffect(() => {
+ if (!isOpen) return;
+ setSelected(0);
+ // Defer focus to the next tick so the DOM has actually mounted.
+ queueMicrotask(() => itemRefs.current[0]?.focus());
+ }, [isOpen]);
+
+ // Move DOM focus with the arrow-key selection so the browser's focus
+ // ring follows, and the currently active button is readable to AT.
+ useEffect(() => {
+ if (!isOpen) return;
+ itemRefs.current[selected]?.focus();
+ }, [selected, isOpen]);
useEffect(() => {
if (!isOpen) return;
- const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') cancel(); };
+ const onKey = (e: KeyboardEvent) => {
+ if (e.key === 'Escape') { cancel(); return; }
+ if (e.key === 'ArrowDown') {
+ e.preventDefault();
+ setSelected(s => (s + 1) % Math.max(1, accounts.length));
+ } else if (e.key === 'ArrowUp') {
+ e.preventDefault();
+ setSelected(s => (s - 1 + accounts.length) % Math.max(1, accounts.length));
+ } else if (e.key === 'Enter') {
+ e.preventDefault();
+ const target = accounts[selected];
+ if (target) pick(target);
+ }
+ };
window.addEventListener('keydown', onKey);
return () => window.removeEventListener('keydown', onKey);
- }, [isOpen, cancel]);
+ }, [isOpen, accounts, selected, pick, cancel]);
if (!isOpen) return null;
@@ -42,13 +72,15 @@ export default function OrbitAccountPicker() {
{t('orbit.accountPickerSub', { url: accounts[0]?.url ?? '' })}
-
- {accounts.map(a => (
- -
+
+ {accounts.map((a, i) => (
+ -