Skip to content

feat: Vim-style keyboard navigation (j/k/gg/G) has no visual indicator showing which issue is currently focused β€” users pressing j/k see no cursor highlight or scroll marker, making the feature effectively invisible and unusableΒ #95

Description

@prince-pokharna

πŸ› Problem Statement

IssueScope documents:

"Vim-style navigation (j/k, gg, G) and keyboard shortcuts for efficiency."

This is an excellent power-user feature. However, a critical piece of the UX is missing: when a user presses j or k, there is no visible focus indicator showing which issue is currently selected. The keyboard navigation works silently β€” the list may scroll, but there is no highlighted row, border, or cursor marker distinguishing the focused issue from unfocused ones.

Without a visible cursor, users cannot:

  • Confirm that keyboard navigation is working at all
  • Know which issue will be opened when they press Enter
  • Use the feature effectively in a list of 50+ issues

This is a classic a11y (accessibility) issue as well β€” WCAG 2.1 SC 2.4.7 requires that keyboard focus is always visible.

πŸ’‘ Proposed Fix

1. Track focusedIndex in Zustand state

// src/store/navigationStore.ts

import { create } from 'zustand';

interface NavigationState {
  focusedIndex: number;
  setFocusedIndex: (index: number) => void;
}

export const useNavigationStore = create<NavigationState>((set) => ({
  focusedIndex: 0,
  setFocusedIndex: (index) => set({ focusedIndex: index }),
}));

2. Apply a focus ring CSS class to the focused issue card

// src/components/IssueList.tsx

const { focusedIndex } = useNavigationStore();

{issues.map((issue, index) => (
  <IssueCard
    key={issue.number}
    issue={issue}
    isFocused={index === focusedIndex}
    id={`issue-card-${index}`}
  />
))}
// src/components/IssueCard.tsx

<div
  className={`issue-card ${isFocused ? 'issue-card--focused' : ''}`}
  tabIndex={isFocused ? 0 : -1}  // Proper a11y tab order
  ref={isFocused ? focusRef : undefined}
>
/* src/index.css or component styles */
.issue-card--focused {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
  background-color: var(--color-surface-elevated);
  box-shadow: 0 0 0 3px var(--color-primary-alpha);
}

3. Scroll the focused card into view automatically

// In keyboard handler:
useEffect(() => {
  const el = document.getElementById(`issue-card-${focusedIndex}`);
  el?.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}, [focusedIndex]);

4. Add a keyboard shortcuts overlay (? key)

Show a modal listing all available shortcuts when the user presses ?.

πŸ“ Files to Modify

File Change
src/store/navigationStore.ts New β€” focusedIndex state
src/components/IssueList.tsx Pass isFocused prop based on index
src/components/IssueCard.tsx Apply .issue-card--focused class + tabIndex
src/hooks/useKeyboardNav.ts Update focus index on j/k/gg/G; scroll into view
src/index.css Add focus ring styles

Suggested labels: bug, accessibility, keyboard-navigation, ux

I would like to work on this. Could you please assign it to me?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions