FocusScopeNode class Null safety

A subclass of FocusNode that acts as a scope for its descendants, maintaining information about which descendant is currently or was last focused.

Please see the FocusScope and Focus widgets, which are utility widgets that manage their own FocusScopeNodes and FocusNodes, respectively. If they aren't appropriate, FocusScopeNodes can be managed directly.

FocusScopeNode organizes FocusNodes into scopes. Scopes form sub-trees of nodes that can be traversed as a group. Within a scope, the most recent nodes to have focus are remembered, and if a node is focused and then removed, the original node receives focus again.

From a FocusScopeNode, calling setFirstFocus, sets the given focus scope as the focusedChild of this node, adopting if it isn't already part of the focus tree.


There are several actors involved in the lifecycle of a FocusNode/FocusScopeNode. They are created and disposed by their owner, attached, detached, and re-parented using a FocusAttachment by their host (which must be owned by the State of a StatefulWidget), and they are managed by the FocusManager. Different parts of the FocusNode API are intended for these different actors.

FocusNodes (and hence FocusScopeNodes) are persistent objects that form part of a focus tree that is a sparse representation of the widgets in the hierarchy that are interested in receiving keyboard events. They must be managed like other persistent state, which is typically done by a StatefulWidget that owns the node. A stateful widget that owns a focus scope node must call dispose from its State.dispose method.

Once created, a FocusNode must be attached to the widget tree via a FocusAttachment object. This attachment is created by calling attach, usually from the State.initState method. If the hosting widget is updated to have a different focus node, then the updated node needs to be attached in State.didUpdateWidget, after calling FocusAttachment.detach on the previous FocusAttachment.

Because FocusNodes form a sparse representation of the widget tree, they must be updated whenever the widget tree is rebuilt. This is done by calling FocusAttachment.reparent, usually from the or State.didChangeDependencies methods of the widget that represents the focused region, so that the BuildContext assigned to the FocusScopeNode can be tracked (the context is used to obtain the RenderObject, from which the geometry of focused regions can be determined).

Creating a FocusNode each time is invoked will cause the focus to be lost each time the widget is built, which is usually not desired behavior (call unfocus if losing focus is desired).

If, as is common, the hosting StatefulWidget is also the owner of the focus node, then it will also call dispose from its State.dispose (in which case the FocusAttachment.detach may be skipped, since dispose will automatically detach). If another object owns the focus node, then it must call dispose when the node is done being used.

Key Event Propagation

The FocusManager receives key events from RawKeyboard and will pass them to the focused nodes. It starts with the node with the primary focus, and will call the onKey callback for that node. If the callback returns false, indicating that it did not handle the event, the FocusManager will move to the parent of that node and call its onKey. If that onKey returns true, then it will stop propagating the event. If it reaches the root FocusScopeNode, FocusManager.rootScope, the event is discarded.

See also:

  • Focus, a widget that manages a FocusNode and provides access to focus information and actions to its descendant widgets.
  • FocusManager, a singleton that manages the primary focus and distributes key events to focused nodes.


FocusScopeNode({String? debugLabel, FocusOnKeyCallback? onKey, bool skipTraversal = false, bool canRequestFocus = true})
Creates a FocusScopeNode. [...]


ancestors Iterable<FocusNode>
An Iterable over the ancestors of this node. [...]
read-only, inherited
canRequestFocus bool
If true, this focus node may request the primary focus. [...]
@mustCallSuper, read / write, inherited
children Iterable<FocusNode>
An iterator over the children of this node.
read-only, inherited
context BuildContext?
The context that was supplied to attach. [...]
read-only, inherited
debugLabel String?
A debug label that is used for diagnostic output. [...]
read / write, inherited
descendants Iterable<FocusNode>
An Iterable over the hierarchy of children below this one, in depth-first order.
read-only, inherited
descendantsAreFocusable bool
If false, will disable focus for all of this node's descendants. [...]
@mustCallSuper, read / write, inherited
enclosingScope FocusScopeNode?
Returns the nearest enclosing scope node above this node, or null if the node has not yet be added to the focus tree. [...]
read-only, inherited
focusedChild FocusNode?
Returns the child of this node that should receive focus if this scope node receives focus. [...]
hasFocus bool
Whether this node has input focus. [...]
read-only, inherited
hashCode int
The hash code for this object. [...]
read-only, inherited
hasListeners bool
Whether any listeners are currently registered. [...]
@protected, read-only, inherited
hasPrimaryFocus bool
Returns true if this node currently has the application-wide input focus. [...]
read-only, inherited
highlightMode FocusHighlightMode
Returns the FocusHighlightMode that is currently in effect for this node.
read-only, inherited
isFirstFocus bool
Returns true if this scope is the focused child of its parent scope.
nearestScope FocusScopeNode
Returns the nearest enclosing scope node above this node, including this node, if it's a scope. [...]
read-only, override
offset Offset
Returns the global offset to the upper left corner of the attached widget's RenderObject, in logical units. [...]
read-only, inherited
onKey FocusOnKeyCallback?
Called if this focus node receives a key event while focused (i.e. when hasFocus returns true). [...]
read / write, inherited
parent FocusNode?
Returns the parent node for this object. [...]
read-only, inherited
rect Rect
Returns the global rectangle of the attached widget's RenderObject, in logical units. [...]
read-only, inherited
runtimeType Type
A representation of the runtime type of the object.
read-only, inherited
size Size
Returns the size of the attached widget's RenderObject, in logical units. [...]
read-only, inherited
skipTraversal bool
If true, tells the focus traversal policy to skip over this node for purposes of the traversal algorithm. [...]
read / write, inherited
traversalChildren Iterable<FocusNode>
An iterator over the children that are allowed to be traversed by the FocusTraversalPolicy.
read-only, inherited
traversalDescendants Iterable<FocusNode>
Returns all descendants which do not have the skipTraversal and do have the canRequestFocus flag set.
read-only, inherited


addListener(VoidCallback listener) → void
Register a closure to be called when the object changes. [...]
attach(BuildContext? context, {FocusOnKeyCallback? onKey}) FocusAttachment
Called by the host StatefulWidget to attach a FocusNode to the widget tree. [...]
@mustCallSuper, inherited
autofocus(FocusNode node) → void
If this scope lacks a focus, request that the given node become the focus. [...]
consumeKeyboardToken() bool
Removes the keyboard token from this focus node if it has one. [...]
debugDescribeChildren() List<DiagnosticsNode>
Returns a list of DiagnosticsNode objects describing this node's children. [...]
debugFillProperties(DiagnosticPropertiesBuilder properties) → void
Add additional properties associated with the node. [...]
dispose() → void
Discards any resources used by the object. After this is called, the object is not in a usable state and should be discarded (calls to addListener and removeListener will throw after the object is disposed). [...]
focusInDirection(TraversalDirection direction) bool
Request to move the focus to the nearest focus node in the given direction, by calling the FocusTraversalPolicy.inDirection method. [...]
nextFocus() bool
Request to move the focus to the next focus node, by calling the method. [...]
noSuchMethod(Invocation invocation) → dynamic
Invoked when a non-existent method or property is accessed. [...]
notifyListeners() → void
Call all the registered listeners. [...]
previousFocus() bool
Request to move the focus to the previous focus node, by calling the FocusTraversalPolicy.previous method. [...]
removeListener(VoidCallback listener) → void
Remove a previously registered closure from the list of closures that are notified when the object changes. [...]
requestFocus([FocusNode? node]) → void
Requests the primary focus for this node, or for a supplied node, which will also give focus to its ancestors. [...]
setFirstFocus(FocusScopeNode scope) → void
Make the given scope the active child scope for this scope. [...]
toDiagnosticsNode({String? name, DiagnosticsTreeStyle? style}) DiagnosticsNode
Returns a debug representation of the object that is used by debugging tools and by DiagnosticsNode.toStringDeep. [...]
toString({DiagnosticLevel minLevel =}) String
A string representation of this object. [...]
toStringDeep({String prefixLineOne = '', String? prefixOtherLines, DiagnosticLevel minLevel = DiagnosticLevel.debug}) String
Returns a string representation of this node and its descendants. [...]
toStringShallow({String joiner = ', ', DiagnosticLevel minLevel = DiagnosticLevel.debug}) String
Returns a one-line detailed description of the object. [...]
toStringShort() String
A brief description of this object, usually just the runtimeType and the hashCode. [...]
unfocus({UnfocusDisposition disposition = UnfocusDisposition.scope}) → void
Removes the focus on this node by moving the primary focus to another node. [...]


operator ==(Object other) bool
The equality operator. [...]