Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

FocusScope

FocusScope — a layout-transparent wrapper that declares a traversal boundary for Tab / Shift+Tab focus cycling.

Public functions

FocusScope

Detailed description

Descendants' tab_index values are scoped to the nearest enclosing FocusScope: two sibling scopes that both number their children 1, 2, 3 never interleave — each scope is an independent, ordered unit within its parent. The TraversalScopePolicy controls what Tab does at the scope's ends:

  • Continue — Tab flows out of the scope into the enclosing scope's next member (grouping only). Use for logical regions in a continuous Tab order, e.g. dock panels.
  • Cycle — Tab wraps within the scope and never leaves via keyboard. Use for modal dialogs.
// A modal dialog whose Tab order is confined to its own content:
FocusScope::new(TraversalScopePolicy::Cycle).child(dialog_body)

Do not Cycle-wrap a popover, menu or dropdown panel. Those are non-modal, and the framework dismisses a non-modal overlay when keyboard focus leaves it — which is what their ARIA patterns (Disclosure, Menu) ask for, and what keeps an open panel from sitting over the focus ring that left it. Trapping focus inside one prevents that dismissal from ever firing. A centered modal needs no wrapper at all: cycle_focus already roots traversal at the topmost centered overlay's content.

Layout & accessibility

FocusScope imposes no layout — it reports its child's natural size and places the child at its own bounds (like Fade). It is a structural boundary, not an AT element: the wrapped child owns its own accessibility semantics. The scope node is never itself a Tab stop (BuildContext::set_traversal_scope forces it non-focusable).

API reference

📖 Full rustdoc API for this module

pub struct FocusScope

Import: use teksilo::widgets::FocusScope;

Wraps a child subtree and declares it a Tab traversal scope. See the module documentation for semantics.

#![allow(unused)]
fn main() {
pub struct FocusScope { /* fields */ }
}

Methods

pub fn new(policy: TraversalScopePolicy) -> Self

Create a traversal scope with the given boundary policy.

pub fn child(mut self, widget: impl teksilo_core::IntoTeksiChild) -> Self

Inline child widget (deferred insertion — the form teksu! lowers to).

pub fn child_opt(self, widget: Option<impl teksilo_core::IntoTeksiChild>) -> Self

Attach widget when it is Some, and do nothing when it is None.

The conditional-child form. teksu!'s if without an else lowers to this, and it is what cond.then(|| w) is for in a builder chain. None adds no arena node, so nothing is laid out, painted, or published to the accessibility tree, and a stack applies no spacing around it.