How to Implement Arrow Key Navigation in a Menu in Batch Script
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:
- Use a variable (
!selected!) to track the current index. - Call a small PowerShell one-liner to wait for a keypress.
- PowerShell will return a specific string (like
"UpArrow","DownArrow", or"Enter") back to our Batch script. - 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$trueparameter 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 thekeyvariable.-nologo -noprofile: These flags suppress the PowerShell startup banner and skip loading the user's profile, reducing the delay between keypresses.
Performance note: Each keypress spawns a new PowerShell process, which introduces a small delay (typically 200–500ms). This is noticeable as a brief pause after each key press before the menu redraws. For most interactive menus this is acceptable, but it means the menu will not feel as instantaneous as a native GUI application.
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
- Selection Tracking: Use a variable to store which line is active.
- 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).
- PowerShell Listener: Use the
[Console]::ReadKey($true).Keymethod for reliable arrow key detection. - Dynamic Rendering: Use a
for /Lloop with indexed variables so adding menu items requires no changes to the display logic. - Action Handling: Use
gotoorcallto 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.