Skip to main content

Keyboard-driven interactive button menus for Python terminal apps

Project description

interactive-buttons-v2

Keyboard-driven interactive button menus for your Python terminal apps.

Navigate with arrow keys, confirm with Enter. Three layout modes, 12 built-in style presets, and optional hotkey bindings. Works in any real terminal on Linux, Windows and macOS.


Installation

pip install interactive-buttons-v2

Requires Python 3.10+ and two lightweight dependencies:

Package Purpose
colorama Cross-platform ANSI color codes
readchar Raw single-keystroke input

Quick example

from interactive_buttons import Button, Component, ButtonStyle, HACKER_STYLE

buttons = [
    Button(label="Continue", value="continue"),
    Button(label="Exit",     value="exit"),
]

comp   = Component(buttons, global_buttons_style=ButtonStyle(**HACKER_STYLE))
choice = comp.column_buttons()

print(f"You chose: {choice}")
> Continue      <- highlighted (selected)
  Exit

Use up / down to navigate and Enter to confirm.


Layout modes

Component exposes three layout methods. Each one blocks until the user confirms a selection and returns that button's value.

Column layout

Buttons are stacked vertically. Navigate with up / down, confirm with Enter.

from interactive_buttons import Button, Component, ButtonStyle, CORPORATE_STYLE

buttons = [
    Button(label="New file",  value="new"),
    Button(label="Open file", value="open"),
    Button(label="Save",      value="save"),
    Button(label="Quit",      value="quit"),
]

comp   = Component(buttons)
choice = comp.column_buttons()
[New file]   <- highlighted
[Open file]
[Save]
[Quit]

Linear (horizontal) layout

Buttons are placed side by side on a single line. Navigate with ← / →, confirm with Enter. Ideal for binary confirmations (Yes / No, OK / Cancel).

from interactive_buttons import Button, Component, ButtonStyle, MINIMAL_STYLE

buttons = [
    Button(label="Yes", value=True),
    Button(label="No",  value=False),
]

comp    = Component(buttons, global_buttons_style=ButtonStyle(**MINIMAL_STYLE))
confirm = comp.linear_buttons()

Matrix (grid) layout

Buttons are arranged in a square grid. Navigate with all four arrow keys, confirm with Enter. The grid side length is ceil(sqrt(len(buttons))).

from interactive_buttons import Button, Component, ButtonStyle, MATRIX_STYLE

buttons = [
    Button(label="Attack",  value="attack"),
    Button(label="Magic",   value="magic"),
    Button(label="Item",    value="item"),
    Button(label="Defend",  value="defend"),
    Button(label="Flee",    value="flee"),
    Button(label="Status",  value="status"),
    Button(label="Options", value="options"),
    Button(label="Save",    value="save"),
    Button(label="Quit",    value="quit"),
]

comp   = Component(buttons, global_buttons_style=ButtonStyle(**MATRIX_STYLE))
action = comp.matrix_buttons()
[Attack]   [Magic]  [Item]
[Defend]   [Flee]   [Status]
[Options]  [Save]   [Quit]

Component options

Parameter Type Default Description
buttons list[Button] - Ordered list of buttons
global_buttons_style ButtonStyle DEFAULT_STYLE Style applied to buttons without a local override
display_index bool False Auto-prefix each button with a digit shortcut (1, 2, …)
index_begin int 1 Starting digit when display_index is active
auto_erase bool False Erase the rendered buttons automatically after selection

Note: display_index=True and per-button ButtonKeyBind cannot be used at the same time. Doing so raises KeyBindError.


Styles

Built-in presets

12 presets are exported from the top-level package as plain dict. Unpack with **:

from interactive_buttons import ButtonStyle, HACKER_STYLE

style = ButtonStyle(**HACKER_STYLE)
  • DEFAULT_STYLE
  • HACKER_STYLE
  • MINIMAL_STYLE
  • MONOCHROME_STYLE
  • CORPORATE_STYLE
  • TERMINAL_RETRO_STYLE
  • MATRIX_STYLE
  • CYBERPUNK_STYLE
  • DANGER_STYLE
  • SUCCESS_STYLE
  • SUNSET_STYLE
  • GHOST_STYLE

Custom style

from colorama import Fore, Back
from interactive_buttons import ButtonStyle, Button, Component

my_style = ButtonStyle(
    text_color=Fore.MAGENTA,
    highlight_color=Back.WHITE,
    spaces_count=4,
    left_decorator="* ",
    right_decorator=" *",
)

comp = Component(buttons, global_buttons_style=my_style)
Parameter Type Description
text_color str ANSI code for the label text color
highlight_color str ANSI code applied to the selected button background
spaces_count int Padding spaces on each side of the label (minimum 2)
left_decorator str String prepended to the label
right_decorator str String appended to the label

Per-button style override

Each Button accepts a local_button_style that overrides the component-level style for that button only:

from interactive_buttons import Button, Component, ButtonStyle, SUCCESS_STYLE, DANGER_STYLE

buttons = [
    Button(label="Confirm", value="confirm", local_button_style=ButtonStyle(**SUCCESS_STYLE)),
    Button(label="Cancel",  value="cancel",  local_button_style=ButtonStyle(**DANGER_STYLE)),
]

comp   = Component(buttons)
choice = comp.linear_buttons()

Key bindings

ButtonKeyBind lets you assign one or more hotkeys to a button. Pressing a bound key moves the cursor to that button, or immediately confirms it if press_on_selection=True.

Basic binding

from interactive_buttons import Button, ButtonKeyBind, Component, ButtonStyle, HACKER_STYLE

save_bind = ButtonKeyBind(b_keys=["s", "1"])
quit_bind = ButtonKeyBind(b_keys=["q", "2"])

buttons = [
    Button(label="Save", value="save", key_bind=save_bind),
    Button(label="Quit", value="quit", key_bind=quit_bind),
]

comp   = Component(buttons, global_buttons_style=ButtonStyle(**HACKER_STYLE))
choice = comp.column_buttons()

Pressing s or 1 jumps to Save. The user still needs Enter to confirm.

Instant-confirm on key press

Set press_on_selection=True to confirm the button the moment its key is pressed, no Enter needed:

yes_bind = ButtonKeyBind(b_keys=["y"], press_on_selection=True)
no_bind  = ButtonKeyBind(b_keys=["n"], press_on_selection=True)

buttons = [
    Button(label="Yes", value=True,  key_bind=yes_bind),
    Button(label="No",  value=False, key_bind=no_bind),
]

comp    = Component(buttons)
confirm = comp.linear_buttons()
# Pressing "y" immediately returns True; pressing "n" immediately returns False.

Case-sensitive keys

By default, key matching is case-insensitive (a and A trigger the same binding). Set case_sensitive=True to distinguish them:

lower_bind = ButtonKeyBind(b_keys=["a"], case_sensitive=True)
upper_bind = ButtonKeyBind(b_keys=["A"], case_sensitive=True)

Accepted characters

Each entry in b_keys must be a single ASCII alphanumeric character (A-Z, a-z, 0-9). Anything else raises KeyBindError at construction time. Each key must also be unique across all buttons in the same Component.

Documentation

Full documentation at interactive-buttons.mbinc.tech.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

interactive_buttons_v2-1.0.1.tar.gz (10.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

interactive_buttons_v2-1.0.1-py3-none-any.whl (16.5 kB view details)

Uploaded Python 3

File details

Details for the file interactive_buttons_v2-1.0.1.tar.gz.

File metadata

  • Download URL: interactive_buttons_v2-1.0.1.tar.gz
  • Upload date:
  • Size: 10.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for interactive_buttons_v2-1.0.1.tar.gz
Algorithm Hash digest
SHA256 89186c9b6ddb9a8979a6ed6e0e0eaf8a98669d0bda4b096b7524e35808a7d3bc
MD5 a61e6fcf0daa3d9afff739ad8e4deb0c
BLAKE2b-256 efef45ea331f74f76cc3ee057f7ae39575f09832d0646e9cb9ee928abb060ccf

See more details on using hashes here.

Provenance

The following attestation bundles were made for interactive_buttons_v2-1.0.1.tar.gz:

Publisher: publish.yml on mbcraft-exe/interactive-buttons-v2

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file interactive_buttons_v2-1.0.1-py3-none-any.whl.

File metadata

File hashes

Hashes for interactive_buttons_v2-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 863263f32fe3a8263068de48eee03d81d707788bc8954308aff2807bc9c411f6
MD5 b81ac147b802e8538e555f8445688051
BLAKE2b-256 59b0c4a44d1dfa8ab60de502cdd8f7b596b2bd4aea975023837490ea27a5b3d9

See more details on using hashes here.

Provenance

The following attestation bundles were made for interactive_buttons_v2-1.0.1-py3-none-any.whl:

Publisher: publish.yml on mbcraft-exe/interactive-buttons-v2

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page