Skip to main content

How to Create a Scrollable Menu Selection in Batch Script

Standard Batch menus require the user to type a number or letter and press Enter. A Scrollable Menu, on the other hand, allows users to see a large list of options and navigate through them, often using pagination if the list exceeds the screen height. While Batch doesn't have a native "scroll component," we can simulate this behavior using loops, variables, and the choice command.

In this guide, we will demonstrate how to build a menu that displays a "window" of options from a larger set.

The Strategy: Windowing

To create a scrollable effect, we track two variables:

  1. Start Index: The first item currently displayed on the screen.
  2. Window Size: How many items the screen can show at once (e.g., 5).

When the user chooses "Next," we increment the Start Index and redraw the screen.

Implementation Script: Paginated Scroll Menu

This script processes a list of items and shows them in a configurable window size at a time.

@echo off
setlocal enabledelayedexpansion

:: -------------------------------------------------------
:: Define data using indexed variables
:: -------------------------------------------------------
set "item1=Apple"
set "item2=Banana"
set "item3=Cherry"
set "item4=Date"
set "item5=Elderberry"
set "item6=Fig"
set "item7=Grape"
set "item8=Honeydew"
set "item9=Iceberg"
set "item10=Jicama"
set "item11=Kiwi"
set "item12=Lemon"

set /a "totalItems=12"
set /a "windowSize=5"
set /a "startIndex=1"

:: -------------------------------------------------------
:: Main Display Loop
:: -------------------------------------------------------
:draw_menu
cls
echo ==========================================
echo SCROLLABLE FRUIT SELECTOR
echo ==========================================
echo.

:: Calculate window bounds
set /a "endIndex=startIndex + windowSize - 1"
if !endIndex! gtr !totalItems! set /a "endIndex=totalItems"

:: Calculate page info
set /a "currentPage=(startIndex - 1) / windowSize + 1"
set /a "totalPages=(totalItems + windowSize - 1) / windowSize"

:: Display current window of items
for /L %%i in (!startIndex!, 1, !endIndex!) do (
call echo [%%i] %%item%%i%%
)

echo.
echo Page !currentPage! of !totalPages! ^(Items !startIndex!-!endIndex! of !totalItems!^)
echo ------------------------------------------

:: Determine available navigation
set /a "nextStart=startIndex + windowSize"
set /a "prevStart=startIndex - windowSize"
if !prevStart! lss 1 set /a "prevStart=1"

set "canNext=0"
set "canPrev=0"
if !nextStart! leq !totalItems! set "canNext=1"
if !startIndex! gtr 1 set "canPrev=1"

:: -------------------------------------------------------
:: Build choice options based on available directions
:: Always use a FIXED key order so position is predictable
:: -------------------------------------------------------
if !canPrev! equ 1 (
if !canNext! equ 1 (
echo [P] Previous [N] Next [X] Exit
echo ------------------------------------------
choice /c PNX /n /m "Select: "
if !errorlevel! equ 1 set "startIndex=!prevStart!" & goto draw_menu
if !errorlevel! equ 2 set "startIndex=!nextStart!" & goto draw_menu
if !errorlevel! equ 3 goto ExitGame
) else (
echo [P] Previous [X] Exit
echo ------------------------------------------
choice /c PX /n /m "Select: "
if !errorlevel! equ 1 set "startIndex=!prevStart!" & goto draw_menu
if !errorlevel! equ 2 goto ExitGame
)
) else (
if !canNext! equ 1 (
echo [N] Next [X] Exit
echo ------------------------------------------
choice /c NX /n /m "Select: "
if !errorlevel! equ 1 set "startIndex=!nextStart!" & goto draw_menu
if !errorlevel! equ 2 goto ExitGame
) else (
echo [X] Exit
echo ------------------------------------------
choice /c X /n /m "Select: "
goto ExitGame
)
)

goto draw_menu

:: -------------------------------------------------------
:: Exit
:: -------------------------------------------------------
:ExitGame
echo.
echo Goodbye^!
pause
exit /b 0

Adding Item Selection

To allow users to select a specific item from the current page, you can add numeric input handling after the navigation:

@echo off
setlocal enabledelayedexpansion

:: -------------------------------------------------------
:: Define data
:: -------------------------------------------------------
set "item1=Server-A"
set "item2=Server-B"
set "item3=Server-C"
set "item4=Server-D"
set "item5=Server-E"
set "item6=Server-F"
set "item7=Server-G"
set "item8=Server-H"

set /a "totalItems=8"
set /a "windowSize=4"
set /a "startIndex=1"

:draw_menu
cls
echo ==========================================
echo SERVER SELECTION MENU
echo ==========================================
echo.

:: Calculate bounds and page info
set /a "endIndex=startIndex + windowSize - 1"
if !endIndex! gtr !totalItems! set /a "endIndex=totalItems"

set /a "currentPage=(startIndex - 1) / windowSize + 1"
set /a "totalPages=(totalItems + windowSize - 1) / windowSize"

:: Display items in the current window
for /L %%i in (!startIndex!, 1, !endIndex!) do (
echo [%%i] !item%%i!
)

echo.
echo Page !currentPage! of !totalPages! (Items !startIndex!-!endIndex! of !totalItems!)
echo ------------------------------------------

:: Build dynamic navigation options
set "navHelp="
set /a "nextStart=startIndex + windowSize"
if !nextStart! leq !totalItems! set "navHelp=[N] Next "
if !startIndex! gtr 1 set "navHelp=!navHelp![P] Previous "

echo !navHelp![X] Exit
echo ------------------------------------------
echo.

set "input="
set /p "input=Enter item number or navigation: "

if not defined input goto draw_menu

:: -------------------------------------------------------
:: Handle Navigation
:: -------------------------------------------------------
if /i "!input!"=="N" (
set /a "newStart=startIndex + windowSize"
if !newStart! leq !totalItems! (
set "startIndex=!newStart!"
) else (
echo.
echo [!] No more pages.
pause
)
goto draw_menu
)

if /i "!input!"=="P" (
set /a "newStart=startIndex - windowSize"
if !newStart! lss 1 set "newStart=1"
set "startIndex=!newStart!"
goto draw_menu
)

if /i "!input!"=="X" (
echo.
echo Goodbye!
endlocal
exit /b
)

:: -------------------------------------------------------
:: Validate and Process Numeric Selection
:: -------------------------------------------------------
set "valid="
:: Check if input matches an index in the current window
for /L %%i in (!startIndex!, 1, !endIndex!) do (
if "!input!"=="%%i" set "valid=1"
)

if defined valid (
:: Robustly expand the selected item using a for loop
for /f "delims=" %%A in ("!input!") do set "selectedName=!item%%A!"
echo.
echo +--------------------------------------
echo You selected: !selectedName!
echo +--------------------------------------
echo.
pause
goto draw_menu
) else (
echo.
echo [ERROR] Invalid selection: "!input!"
echo Please enter N, P, X, or a number between !startIndex! and !endIndex!.
echo.
pause
goto draw_menu
)

Enhancing the Scroll: The "Current Selection" Highlight

For a more modern look, you can use ANSI escape codes to visually highlight a specific item in the list.

:: Requires ESC character setup:
:: for /F "delims=" %%a in ('echo prompt $E ^| cmd') do set "ESC=%%a"

:: Inside the display loop, highlight the selected item using reverse video
for /L %%j in (!startIndex!, 1, !endIndex!) do (
if %%j==!currentSelection! (
echo !ESC![7m [%%j] !item%%j! !ESC![0m
) else (
echo [%%j] !item%%j!
)
)

Key Considerations for Scrollable Menus

  1. Screen Flicker: Redrawing the entire screen with cls causes a visible flicker. On Windows 10/11, you can use ANSI cursor positioning commands to update only the lines that have changed, making the scroll look smoother.
  2. Navigation Keys: The choice command provides instant single-key input without pressing Enter, but it does not support arrow keys. The set /p command supports typing numbers of any length but requires pressing Enter. Choose based on your needs, choice for simple navigation, set /p for item selection by number.
  3. Boundary Checks: Always ensure your startIndex never goes below 1 and your endIndex doesn't exceed the total count. The scripts above handle this by validating before applying navigation changes.
  4. Dynamic Navigation Options: Only show "Next Page" when there are more items beyond the current window, and "Previous Page" when the user is not on the first page. This prevents confusion about available actions.

Conclusion

A scrollable menu significantly improves the user experience for Batch scripts that manage large inventories of data (like a list of 50 servers or 100 backup sets). By implementing "windowing" logic, you keep the interface clean and manageable, allowing your users to navigate complex datasets with ease and clarity.