# Test FocusZone basics
zone = FocusZone(
id="source-browser",
item_selector="tr[data-selectable='true']",
data_attributes=("job-id", "plugin-name"),
on_focus_change="updatePreview"
)
assert zone.id == "source-browser"
assert zone.has_items() == True
assert zone.get_hidden_input_id("job-id") == "source-browser-job-id"
# Test to_js_config
config = zone.to_js_config()
assert config["id"] == "source-browser"
assert config["itemSelector"] == "tr[data-selectable='true']"
assert config["onFocusChange"] == "updatePreview"Focus Zone
Configuration for focusable containers with navigable items.
FocusZone
A container that can receive focus and contains navigable items. Each zone tracks its own focus state and can have independent navigation patterns.
FocusZone
def FocusZone(
id:str, item_selector:Optional[str]=None, navigation:Union[NavigationPattern, LinearVertical]=<factory>,
navigation_throttle_ms:int=0, item_focus_classes:tuple[str, ...]=('ring-2', 'ring-primary'),
item_focus_attribute:str='data-focused',
zone_focus_classes:tuple[str, ...]=('ring-2', 'ring-primary', 'inset-ring-2'),
data_attributes:tuple[str, ...]=(), on_focus_change:Optional[str]=None, on_navigate:Optional[str]=None,
on_zone_enter:Optional[str]=None, on_zone_leave:Optional[str]=None, scroll_behavior:str='smooth',
scroll_block:str='nearest', hidden_input_prefix:str='', initial_index:int=0
)->None:
A focusable container with navigable items.
# Test scroll-only zone
from cjm_fasthtml_keyboard_navigation.core.navigation import ScrollOnly
preview_zone = FocusZone(
id="preview-panel",
item_selector=None,
navigation=ScrollOnly()
)
assert preview_zone.has_items() == False
assert preview_zone.navigation.name == "scroll_only"# Test with custom hidden input prefix
zone_with_prefix = FocusZone(
id="my-zone",
hidden_input_prefix="kb",
data_attributes=("file-path",)
)
assert zone_with_prefix.get_hidden_input_id("file-path") == "kb-file-path"