Yes, it was never specified that it worked that way.
Still, it worked from JavaFX 8 through 18, and the change hit silently.
Now there is basically no reason anymore to override it at all.
*Typical Use Cases*
Usually it's done for focus delegation.
Similar to the FakeFocusTextField - just without faking it.
Most often, it's used to delegate the focus to an inner subcomponent.
That's also what's done in the codebase I'm working with.
*Overriding requestFocus is not useful anymore*
At the moment, requestFocus works reliably for mouse input but not for
keyboard events.
A mechanism that only works reliably in one case but not in another
automatically leads to
corner cases when used.
So there is basically no point anymore in overriding it.
If we don't improve the API, this should at least be documented.
*How common is it*
I scanned 44 JavaFX libraries and applications and found 9 genuine
overrides in three
codebases: OpenJFX (FakeFocusTextField), JFoenix (copied it almost verbatim
as
FakeFocusJFXTextField), and JabRef (five layout panes forwarding focus
inward).
But in the codebase I'm working with, I see about 50 cases.
So it's rare in libraries, but it might be more common in application code.
*Documenting that overriding is unsupported would help*
We probably can't make the method final, because it would be a
source-incompatible change.
But we could document that it's no longer supposed to be overridden (if we
don't improve
the API).
Maybe something like the following:
* @apiNote Overriding this method is not supported, as not all focus
changes are
* routed through it; focus acquired by keyboard traversal is set directly.
* To observe focus changes, listen to {@link Scene#focusOwnerProperty()}.
Other focus-related methods aren't overridable either:
Node.requestFocusTraversal is final,
and Node.setFocused is protected final.
So documenting this would just make the existing direction explicit.
*Need for better API exists*
The recurring discussions regarding focus are probably an indication that
all this is
important.
Spinner and ComboBoxPopupControl (used by ComboBox and DatePicker) both
block traversal
into their own subtree by installing a custom Algorithm for the
ParentTraversalEngine
which returns null.
But that is an internal API, not accessible to application developers
without --add-exports.
The project I currently work on uses it too, accessed that way.
Andy's draft PR covers it:
https://github.com/andy-goryachev-oracle/jfx/pull/14
It adds a public javafx.scene.TraversalPolicy and Parent.traversalPolicy,
and it already
replaces the Algorithm in SpinnerSkin with a single setTraversalPolicy(...)
call.
That looks like exactly the right direction.
Greetings
Florian Kirmaier
On Thu, 30 Jul 2026 at 02:34, Martin Fox <[email protected]> wrote:
> requestFocus() is called *before* a node receives focus. Given the way
> it’s named it certainly looks like a way of initiating focus negotiation,
> not finalizing it. And it’s been possible to override this routine and
> re-direct focus since at least JavaFX 8. There’s one instance in Controls
> that uses it for exactly this purpose (the dreaded FakeFocusTextField).
>
> With that said it’s a very weak framework for focus negotiation. For
> example it doesn’t allow ComboBox and Spinner to re-direct focus away from
> sub-nodes. I can think of a few message-based ways of negotiating focus
> that would cover a lot more ground. And for API compatibility I would
> probably initiate those negotiations from requestFocus(). It is the
> beginning of establishing focus, not the end. The end of focus negotiation
> (such as it is) occurs when the node becomes the scene’s focus owner.
> There’s no direct way for a node to determine when that happens beyond
> monitoring the scene’s focusOwner property.
>
> Florian, why are you overriding requestFocus() to begin with?
>
> Martin
>
> > On Jul 29, 2026, at 5:14 PM, Kevin Rushforth <[email protected]>
> wrote:
> >
> > I said something similar in the JBS issue about this being previously
> undocumented behavior. I agree with Michael on this issue.
> >
> > -- Kevin
> >
> >
> > On 7/29/2026 12:19 PM, Michael Strauß wrote:
> >> requestFocus() was never specified to be called when focus changed,
> >> which is also reflected in its name: it's not called onFocusChanged()
> >> or something like it, it suggests a request only.
> >>
> >> You point out that previously, an application could "decide what to do
> >> when a node receives focus. For example, a node could pass the focus
> >> on to another one."
> >>
> >> I don't think that we should be supporting any attempt to subvert the
> >> focus system, it's just not worth it. The Node.setFocused() situation
> >> is bad enough as it is. Most legitimate use cases for hacks like that
> >> can be solved by a focus delegation system, which seems to be due for
> >> our annual discussion round.
> >>
> >> So I'm in favor of doing nothing here, except maybe documenting that
> >> you shouldn't override requestFocus().
> >
>
>