Skip to main content

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 policyFlutter policyTypical use
widgetOrderWidgetOrderTraversalPolicyOrdinary forms laid out in intended tab order
readingOrderReadingOrderTraversalPolicyLayouts where visual reading order should drive focus
orderedOrderedTraversalPolicyForms 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,
  • FdcFocusOptions controls traversal policy and scope boundaries.

This separation prevents application-level tab order from overriding component-specific interaction contracts.