# Keyboard Hints Modal


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

## Key Display

``` python
from fasthtml.common import to_xml

# Single key
html = to_xml(_render_key_combo("Space"))
assert "kbd" in html
assert "Space" in html
assert "+" not in html.split("kbd")[0]  # no plus before first kbd

# Multi-key combo
html = to_xml(_render_key_combo("Ctrl+Shift+\u2191"))
assert html.count("kbd") >= 3  # 3 kbd elements (tag appears in open+close)
assert "Ctrl" in html
assert "Shift" in html
assert "\u2191" in html
print("Key display tests passed")
```

    Key display tests passed

## Hint Row & Group

``` python
# Test hint row
row_html = to_xml(_render_hint_row("Ctrl+Z", "Undo last action"))
assert "Ctrl" in row_html
assert "Z" in row_html
assert "Undo last action" in row_html

# Test modal group
group_html = to_xml(_render_modal_group("Editing", [
    ("Enter", "Enter split mode"),
    ("Escape", "Exit split mode"),
]))
assert "Editing" in group_html
assert "Enter split mode" in group_html
assert "Exit split mode" in group_html
print("Hint row and group tests passed")
```

    Hint row and group tests passed

## Modal Body

``` python
from cjm_fasthtml_keyboard_navigation.core.focus_zone import FocusZone
from cjm_fasthtml_keyboard_navigation.core.actions import KeyAction
from cjm_fasthtml_keyboard_navigation.core.manager import ZoneManager

# Build a test manager with two zones and some actions
z1 = FocusZone(id="seg")
z2 = FocusZone(id="align")
test_manager = ZoneManager(
    zones=(z1, z2),
    actions=(
        KeyAction(key="Enter", js_callback="x", description="Enter split mode", hint_group="Editing"),
        KeyAction(key="Escape", js_callback="x", description="Exit split mode", hint_group="Editing"),
        KeyAction(key="Backspace", htmx_trigger="x", description="Merge with previous", hint_group="Editing"),
        KeyAction(key="z", modifiers=frozenset({"ctrl"}), htmx_trigger="x", description="Undo", hint_group="Editing"),
        KeyAction(key=" ", js_callback="x", description="Play audio", hint_group="Audio"),
    ),
    prev_zone_key="ArrowLeft",
    next_zone_key="ArrowRight",
)

body_html = to_xml(_render_modal_body(test_manager))
assert "Navigation" in body_html
assert "Navigate items" in body_html
assert "Switch panel" in body_html
assert "Editing" in body_html
assert "Enter split mode" in body_html
assert "Audio" in body_html
assert "Play audio" in body_html
print("Modal body tests passed")
```

    Modal body tests passed

## Trigger Button

------------------------------------------------------------------------

<a
href="https://github.com/cj-mills/cjm-fasthtml-keyboard-navigation/blob/main/cjm_fasthtml_keyboard_navigation/components/hints_modal.py#L117"
target="_blank" style="float:right; font-size:smaller">source</a>

### render_keyboard_hints_trigger

``` python

def render_keyboard_hints_trigger(
    modal_id:str='kb-hints-modal', # ID of the modal dialog to open
    icon_size:int=4, # lucide icon size
)->Button: # ghost button with keyboard icon

```

*Render a keyboard icon button that opens the hints modal.*

``` python
trigger = render_keyboard_hints_trigger()
html = to_xml(trigger)
assert "keyboard" in html.lower() or "svg" in html  # has icon
assert "showModal" in html
assert "kb-hints-modal" in html
assert 'title="Keyboard shortcuts (?)"' in html
print("Trigger button tests passed")
```

    Trigger button tests passed

## Question Mark Key Listener

``` python
listener = _render_question_mark_listener("kb-hints-modal")
html = to_xml(listener)
assert "keydown" in html
assert "e.key === '?'" in html
assert "showModal" in html
assert "INPUT" in html  # skips input fields
assert "TEXTAREA" in html
assert "isContentEditable" in html
print("Question mark listener tests passed")
```

    Question mark listener tests passed

## Full Modal Component

------------------------------------------------------------------------

<a
href="https://github.com/cj-mills/cjm-fasthtml-keyboard-navigation/blob/main/cjm_fasthtml_keyboard_navigation/components/hints_modal.py#L164"
target="_blank" style="float:right; font-size:smaller">source</a>

### render_keyboard_hints_modal

``` python

def render_keyboard_hints_modal(
    manager:ZoneManager, # keyboard zone manager with actions configured
    modal_id:str='kb-hints-modal', # HTML ID for the modal dialog
    include_navigation:bool=True, # include \u2191/\u2193 navigation hint
    include_zone_switch:bool=True, # include zone switch hint (auto-hidden for single zone)
    enable_question_mark_key:bool=True, # add global `?` key listener
    title:str='Keyboard Shortcuts', # modal title text
)->tuple[FT, FT, FT]: # (modal_dialog, trigger_button, question_mark_script)

```

*Render a modal-based keyboard shortcut reference.*

Returns three components: - `modal_dialog`: The Dialog element (place
anywhere in page) - `trigger_button`: Small keyboard icon button (place
in step header) - `question_mark_script`: Global `?` key listener Script
(place in page)

If `enable_question_mark_key` is False, `question_mark_script` is an
empty Div.

``` python
# Test with the dual-zone manager from above
modal_dialog, trigger, qm_script = render_keyboard_hints_modal(test_manager)

modal_html = to_xml(modal_dialog)
trigger_html = to_xml(trigger)
script_html = to_xml(qm_script)

# Modal structure
assert 'id="kb-hints-modal"' in modal_html
assert 'modal-box' in modal_html
assert 'modal-backdrop' in modal_html
assert 'Keyboard Shortcuts' in modal_html
assert 'Navigation' in modal_html
assert 'Editing' in modal_html
assert 'Audio' in modal_html
assert '\u2715' in modal_html  # close button

# Trigger
assert 'showModal' in trigger_html
assert 'kb-hints-modal' in trigger_html

# Question mark listener
assert 'keydown' in script_html
assert "e.key === '?'" in script_html

# Test with question mark key disabled
_, _, no_qm = render_keyboard_hints_modal(test_manager, enable_question_mark_key=False)
no_qm_html = to_xml(no_qm)
assert 'keydown' not in no_qm_html  # no listener
assert 'display:none' in no_qm_html  # empty placeholder

# Test single-zone manager (no zone switch hint)
single_manager = ZoneManager(
    zones=(z1,),
    actions=(KeyAction(key=" ", js_callback="x", description="Select", hint_group="Actions"),),
)
single_modal, _, _ = render_keyboard_hints_modal(single_manager)
single_html = to_xml(single_modal)
assert 'Switch panel' not in single_html  # no zone switch for single zone
assert 'Navigate items' in single_html
assert 'Select' in single_html

print("Full modal component tests passed")
```

    Full modal component tests passed
