# Action Buttons


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

## HTMX Trigger Expression Builder

Build HTMX trigger expressions for keyboard events.

**Note:** These triggers are only used when `use_htmx_triggers=True`. By
default, buttons are triggered programmatically by JavaScript via
`triggerClick()`, which respects zone and mode restrictions.

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

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

### build_htmx_trigger

``` python

def build_htmx_trigger(
    key:str, # JavaScript key name
    modifiers:frozenset[str]=frozenset(), # modifier keys
    input_selector:str='input, textarea, select, [contenteditable]', # input elements to exclude
)->str: # HTMX trigger expression

```

*Build HTMX trigger expression for keyboard event.*

``` python
# Test trigger expressions
# Simple key
trigger = build_htmx_trigger(" ")
assert "key==' '" in trigger
assert "from:body" in trigger

# With modifiers
trigger = build_htmx_trigger("ArrowUp", frozenset({"shift"}))
assert "key=='ArrowUp'" in trigger
assert "shiftKey" in trigger

# Multiple modifiers
trigger = build_htmx_trigger("s", frozenset({"ctrl", "shift"}))
assert "ctrlKey" in trigger
assert "shiftKey" in trigger
```

## Single Action Button

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

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

### render_action_button

``` python

def render_action_button(
    action:KeyAction, # the action configuration
    url:str, # POST URL for the action
    target:str, # HTMX target selector
    include:str='', # hx-include selector
    swap:str='outerHTML', # hx-swap value
    vals:dict | None=None, # hx-vals dictionary (JSON values to include in request)
    use_htmx_trigger:bool=False, # use hx-trigger (False = JS triggerClick only)
    input_selector:str='input, textarea, select, [contenteditable]', # inputs to exclude from trigger
)->Button | None: # hidden button or None if not HTMX action

```

*Render a hidden HTMX button for a keyboard action.*

``` python
# Test action button - default (no hx-trigger, JS handles triggering)
from fasthtml.common import to_xml

action = KeyAction(
    key=" ",
    htmx_trigger="toggle-btn",
    description="Toggle"
)

btn = render_action_button(
    action,
    url="/toggle",
    target="#list",
    include="#job-id"
)

assert btn is not None
html = to_xml(btn)
assert 'id="toggle-btn"' in html
assert 'hx-post="/toggle"' in html
assert 'hx-target="#list"' in html
# No hx-trigger by default - JavaScript handles triggering
assert 'hx-trigger' not in html
# No hx-vals by default
assert 'hx-vals' not in html
```

``` python
# Test with hx-trigger enabled
btn_with_trigger = render_action_button(
    action,
    url="/toggle",
    target="#list",
    use_htmx_trigger=True
)
html = to_xml(btn_with_trigger)
assert 'hx-trigger=' in html
assert "key==' '" in html

# Test with vals parameter
btn_with_vals = render_action_button(
    action,
    url="/reorder",
    target="#queue",
    vals={"direction": "up"}
)
html = to_xml(btn_with_vals)
assert 'hx-vals=' in html
assert '"direction"' in html
assert '"up"' in html

# Non-HTMX action returns None
js_action = KeyAction(
    key="Enter",
    js_callback="doSomething"
)

btn = render_action_button(js_action, "/unused", "#unused")
assert btn is None
```

## Action Buttons Container

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

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

### render_action_buttons

``` python

def render_action_buttons(
    manager:ZoneManager, # the zone manager configuration
    url_map:dict[str, str], # action button ID -> URL
    target_map:dict[str, str], # action button ID -> target selector
    include_map:dict[str, str] | None=None, # action button ID -> include selector
    swap_map:dict[str, str] | None=None, # action button ID -> swap value
    vals_map:dict[str, dict] | None=None, # action button ID -> hx-vals dict
    use_htmx_triggers:bool=False, # use hx-trigger (False = JS triggerClick only)
    container_id:str='kb-action-buttons', # container element ID
)->Div: # container with all action buttons

```

*Render all hidden HTMX action buttons for keyboard navigation.*

``` python
# Test action buttons container - default (no hx-trigger)
from cjm_fasthtml_keyboard_navigation.core.focus_zone import FocusZone

zone = FocusZone(id="list", item_selector="li")

manager = ZoneManager(
    zones=(zone,),
    actions=(
        KeyAction(key=" ", htmx_trigger="toggle-btn"),
        KeyAction(key="Delete", htmx_trigger="delete-btn"),
        KeyAction(key="Enter", js_callback="edit"),  # No button for this
    )
)

container = render_action_buttons(
    manager,
    url_map={
        "toggle-btn": "/toggle",
        "delete-btn": "/delete"
    },
    target_map={
        "toggle-btn": "#list",
        "delete-btn": "#list"
    }
)

html = to_xml(container)
assert 'id="kb-action-buttons"' in html
assert 'id="toggle-btn"' in html
assert 'id="delete-btn"' in html
# Should not have hx-trigger by default
assert 'hx-trigger' not in html
# Should not have a button for js_callback action
assert html.count('<button') == 2
```

``` python
# Test with vals_map
manager_with_reorder = ZoneManager(
    zones=(zone,),
    actions=(
        KeyAction(key="ArrowUp", modifiers=frozenset({"shift"}), htmx_trigger="reorder-up-btn"),
        KeyAction(key="ArrowDown", modifiers=frozenset({"shift"}), htmx_trigger="reorder-down-btn"),
    )
)

container_with_vals = render_action_buttons(
    manager_with_reorder,
    url_map={
        "reorder-up-btn": "/reorder",
        "reorder-down-btn": "/reorder"
    },
    target_map={
        "reorder-up-btn": "#queue",
        "reorder-down-btn": "#queue"
    },
    vals_map={
        "reorder-up-btn": {"direction": "up"},
        "reorder-down-btn": {"direction": "down"}
    }
)

html = to_xml(container_with_vals)
assert 'id="reorder-up-btn"' in html
assert 'id="reorder-down-btn"' in html
assert '"direction": "up"' in html
assert '"direction": "down"' in html
```
