Keyboard navigation focus zone and action factories for the card stack.
create_card_stack_focus_zone
Creates a FocusZone configured for the card stack viewport. Uses ScrollOnly navigation since all navigation is handled via HTMX button triggers, not the keyboard library’s built-in item navigation.
def create_card_stack_focus_zone( ids:CardStackHtmlIds, # HTML IDs for this card stack instance on_focus_change:Optional=None, # JS callback name on focus change hidden_input_prefix:Optional=None, # Prefix for keyboard nav hidden inputs data_attributes:Tuple=(), # Data attributes to track on focused items)->FocusZone: # Configured focus zone for the card stack
# Test multi-instance: different prefixes produce different callback namesconfig_a = CardStackConfig(prefix="text")config_b = CardStackConfig(prefix="vad")btn_a = CardStackButtonIds(prefix="text")btn_b = CardStackButtonIds(prefix="vad")ids_a = CardStackHtmlIds(prefix="text")ids_b = CardStackHtmlIds(prefix="vad")actions_a = create_card_stack_nav_actions(ids_a.card_stack, btn_a, config_a)actions_b = create_card_stack_nav_actions(ids_b.card_stack, btn_b, config_b)# HTMX triggers are different (different button IDs)assert actions_a[0].htmx_trigger != actions_b[0].htmx_trigger# JS callbacks are different (different prefixes)assert actions_a[2].js_callback =="text_jumpPageUp"assert actions_b[2].js_callback =="vad_jumpPageUp"print("Multi-instance action tests passed!")
Multi-instance action tests passed!
build_card_stack_url_map
Returns a dict mapping all card stack button IDs to their route URLs, for use as (or merged into) the url_map parameter of render_keyboard_system.
The keyboard system uses this map to create hidden HTMX buttons in the DOM. The JS callbacks (page jump, first/last) and the HTMX-triggered actions (nav up/down) both rely on these buttons existing.
def build_card_stack_url_map( button_ids:CardStackButtonIds, # Button IDs for this card stack instance urls:CardStackUrls, # URL bundle for routing)->Dict: # Mapping of button ID -> route URL
Build url_map for render_keyboard_system with all card stack navigation buttons.
Returns a dict mapping button IDs to URLs for all navigation actions: nav_up, nav_down, nav_first, nav_last, nav_page_up, nav_page_down.
Merge with consumer’s own action URLs when building the keyboard system: url_map = {build_card_stack_url_map(btn_ids, urls), my_action_urls}
Renders hidden HTMX buttons for the JS-callback-triggered navigation actions (page jump, first/last). These are NOT created by render_keyboard_system because the corresponding KeyAction definitions use js_callback instead of htmx_trigger.
The full chain is: 1. Keyboard press → KeyAction with js_callback 2. Keyboard library calls window['cs0_jumpPageUp']() 3. Global wrapper calls window.cardStacks['cs0'].jumpPageUp() 4. JS function calls document.getElementById('cs0-btn-nav-page-up').click() 5. Hidden button fires HTMX POST to the route
Note: nav_up/nav_down buttons are created by render_keyboard_system (since those KeyActions use htmx_trigger). This function creates the remaining 4 navigation buttons that the keyboard system skips.
def render_card_stack_action_buttons( button_ids:CardStackButtonIds, # Button IDs for this card stack instance urls:CardStackUrls, # URL bundle for routing ids:CardStackHtmlIds, # HTML IDs (for hx-include of focused_index_input))->FT: # Div containing hidden action buttons
Render hidden HTMX buttons for JS-callback-triggered navigation actions.
Creates buttons for: page_up, page_down, first, last. These are clicked programmatically by the card stack’s JS functions. Must be included in the DOM alongside the keyboard system’s own buttons.
from fasthtml.common import to_xml# Test render_card_stack_action_buttons_reset_prefix_counter()config = CardStackConfig()ids = CardStackHtmlIds(prefix=config.prefix)btn_ids = CardStackButtonIds(prefix=config.prefix)buttons_div = render_card_stack_action_buttons(btn_ids, urls, ids)html = to_xml(buttons_div)# Verify all 4 hidden buttons are present with correct IDsassert btn_ids.nav_page_up in htmlassert btn_ids.nav_page_down in htmlassert btn_ids.nav_first in htmlassert btn_ids.nav_last in html# Verify HTMX post URLsassert urls.nav_page_up in htmlassert urls.nav_page_down in htmlassert urls.nav_first in htmlassert urls.nav_last in html# Verify hx-include references focused_index_inputassert ids.focused_index_input in html# Verify hidden class (not inline style)assert'class="hidden"'in html# Verify nav_up/nav_down are NOT included (keyboard system handles those)assert btn_ids.nav_up notin htmlassert btn_ids.nav_down notin htmlprint("render_card_stack_action_buttons tests passed!")