Skip to content

How to Implement Arrow Key Navigation in a Menu in Batch Script

Learn how to create an interactive Batch script menu with arrow key navigation and Enter selection using PowerShell integration for modern terminal control.

Standard Batch menus rely on the user typing a key and pressing Enter, or using the choice command for single-key input. However, the most intuitive way to navigate a list is using the Arrow Keys and the Enter key. While the native Batch environment doesn't directly return "Arrow Key" codes, we can use a small PowerShell helper inside our script to capture these inputs and create a modern, high-end menu experience.

In this guide, we will demonstrate how to build a menu with a highlighted selection that moves up and down using the arrow keys.

The Strategy: The Hybrid Input Loop

Since Batch cannot easily detect the "Up Arrow" key, our script will:

  1. Use a variable (!selected!) to track the current index.
  2. Call a small PowerShell one-liner to wait for a keypress.
  3. PowerShell will return a specific string (like "UpArrow", "DownArrow", or "Enter") back to our Batch script.
  4. Batch will update the index and redraw the screen.

Implementation Script

This script creates a 3-item menu that you can navigate with Up/Down and select with Enter.

@echo off
setlocal enabledelayedexpansion

:: 1. Setup ANSI Colors
for /F %%a in ('echo prompt $E ^| cmd') do set "ESC=%%a"

if not defined ESC (
    echo [ERROR] Could not generate ANSI escape character.
    pause
    exit /b 1
)

set "HL=!ESC![7m"
set "RS=!ESC![0m"

:: Define menu items using indexed variables
set "item1=Start Application"
set "item2=Settings"
set "item3=Exit"
set "itemCount=3"

set "selection=1"

:menu_loop
cls
echo ==========================================
echo       ARROW KEY NAVIGATION MENU
echo ==========================================
echo   Use Up/Down arrows and press ENTER
echo ------------------------------------------

:: 2. Display items with highlight on the selected item
for /L %%i in (1, 1, !itemCount!) do (
    if !selection!==%%i (
        echo !HL!  [%%i] !item%%i! !RS!
    ) else (
        echo   [%%i] !item%%i!
    )
)

echo ------------------------------------------

:: 3. Capture Arrow Keys via PowerShell
for /F "delims=" %%K in ('powershell -nologo -noprofile -command "[Console]::ReadKey($true).Key"') do set "key=%%K"

:: 4. Process the key
if "!key!"=="UpArrow" (
    set /a "selection-=1"
    if !selection! lss 1 set "selection=!itemCount!"
)
if "!key!"=="DownArrow" (
    set /a "selection+=1"
    if !selection! gtr !itemCount! set "selection=1"
)
if "!key!"=="Enter" goto :action

goto menu_loop

:action
:: Handle the Exit option
if !selection!==!itemCount! (
    echo.
    echo Exiting...
    endlocal
    exit /b
)

echo.
echo You selected: !item%selection%!
pause
goto menu_loop

How the PowerShell Integration Works

The magic happens in this line:

powershell -nologo -noprofile -command "[Console]::ReadKey($true).Key"
  • [Console]::ReadKey($true): Tells the console to stop and wait for a single keypress. The $true parameter suppresses the character from being echoed to the screen.
  • .Key: Returns the name of the key pressed (e.g., UpArrow, DownArrow, Enter, A, Escape).
  • for /F "delims=" %%K in (...): Batch captures the output of this PowerShell command and stores it in the key variable.
  • -nologo -noprofile: These flags suppress the PowerShell startup banner and skip loading the user's profile, reducing the delay between keypresses.

Dynamic Item Count

The implementation above uses indexed variables (item1, item2, item3) and a for /L loop, making it easy to add or remove items without modifying the display logic. To add a new option, simply define a new itemN variable and increment itemCount:

set "item4=View Logs"
set "item5=Restart Service"
set "itemCount=5"

The display loop, boundary wrapping, and highlight logic all adapt automatically.

Improving Appearance with ANSI

We use ESC[7m which is the Reverse Video (Invert Colors) ANSI code. This swaps the foreground and background colors of the selected line, creating a "highlight bar" that moves as the user presses the arrow keys. The ESC[0m reset code returns subsequent text to normal formatting.

You can also combine the highlight with color codes for a more distinctive selection:

:: Green highlighted selection bar
set "HL=!ESC![7;92m"
set "RS=!ESC![0m"

Summary Checklist

  1. Selection Tracking: Use a variable to store which line is active.
  2. Boundary Logic: Ensure the selection wraps around (e.g., pressing Up at Item 1 jumps to the last item, pressing Down at the last item jumps to Item 1).
  3. PowerShell Listener: Use the [Console]::ReadKey($true).Key method for reliable arrow key detection.
  4. Dynamic Rendering: Use a for /L loop with indexed variables so adding menu items requires no changes to the display logic.
  5. Action Handling: Use goto or call to trigger logic based on the final selection once Enter is pressed.

Conclusion

By bridging Batch with a tiny bit of PowerShell, you can unlock rich user interaction patterns that were previously impossible. Arrow key navigation turns a simple menu into a fully interactive terminal application, providing your users with a familiar, intuitive, and modern way to control your automation tools.

Navigation