Focus Management
FD Components provides suite-level focus traversal defaults for data-entry applications, while still using Flutter's native focus system underneath.
Configure the application default through FdcApp.focus:
FdcApp(
focus: const FdcFocusOptions(
traversalPolicy: FdcFocusTraversalPolicy.widgetOrder,
wrapTraversalGroup: true,
),
child: const DataEntryPage(),
)
Traversal policies
FdcFocusTraversalPolicy maps to Flutter traversal policies:
| FDC policy | Flutter policy | Typical use |
|---|---|---|
widgetOrder | WidgetOrderTraversalPolicy | Ordinary forms laid out in intended tab order |
readingOrder | ReadingOrderTraversalPolicy | Layouts where visual reading order should drive focus |
ordered | OrderedTraversalPolicy | Forms using explicit FocusTraversalOrder values |
widgetOrder is the default because ordinary forms usually already declare fields in the intended traversal order.
Local subtree override
Use FdcFocusScope when one form or panel needs different behavior:
FdcFocusScope(
options: const FdcFocusOptions(
traversalPolicy: FdcFocusTraversalPolicy.readingOrder,
),
child: const AddressForm(),
)
The nearest scope wins for that subtree.
A common architecture is:
FdcApp.focus
application default
↓
FdcFocusScope
local form override
↓
FDC editors and controls
Traversal group boundary
By default, an FDC focus scope wraps its child in Flutter's FocusTraversalGroup:
const FdcFocusOptions(
wrapTraversalGroup: true,
)
Disable this when the host application already owns the traversal group for that subtree:
FdcFocusScope(
options: const FdcFocusOptions(
wrapTraversalGroup: false,
),
child: const EmbeddedEditorPanel(),
)
This prevents FDC from inserting an additional traversal boundary while still providing the scoped options to descendants.
Ordered traversal
For explicit traversal order:
FdcFocusScope(
options: const FdcFocusOptions(
traversalPolicy: FdcFocusTraversalPolicy.ordered,
),
child: Column(
children: [
FocusTraversalOrder(
order: const NumericFocusOrder(1),
child: customerCodeEdit,
),
FocusTraversalOrder(
order: const NumericFocusOrder(2),
child: customerNameEdit,
),
],
),
)
The FDC option selects OrderedTraversalPolicy; Flutter's native order objects still define the actual order.
Reading resolved focus settings
Inside a locally scoped subtree:
final options = FdcFocusScope.of(context);
Listening and non-listening lookup APIs are available:
final current = FdcFocusScope.maybeOf(context);
final initial = FdcFocusScope.maybeOfNonListening(context);
Use listening lookup in dependency-driven UI code and non-listening lookup for initialization paths that must not subscribe to inherited changes.
Focus behavior and grid/editor UX
Focus traversal configuration is separate from component-specific keyboard behavior.
For example:
- editor Enter/Escape behavior belongs to the editor lifecycle,
- grid arrow/PageUp/PageDown behavior belongs to grid navigation,
- header filter focus rules belong to the grid filter UI,
FdcFocusOptionscontrols traversal policy and scope boundaries.
This separation prevents application-level tab order from overriding component-specific interaction contracts.