1. Abstract: Controls that are derived from ButtonBase generally represent an operation that is triggered by the control. In many cases, the control also reflects whether the operation can currently be invoked (i.e. whether the control is enabled or disabled), or whether the operation is currently running. Software patterns like MVVM often encapsulate this behavior for the purpose of decoupling business logic from UI code.
2. Implementation: I propose adding the following interface that represents the entirety of such an operation: interface Command<T> { ReadOnlyBooleanProperty canExecuteProperty(); ReadOnlyBooleanProperty executingProperty(); void execute(); void execute(T parameter); } An application's business logic can expose operations as implementations of the Command interface, and define the conditions when the operation can be executed. Additionally, ButtonBase should be extended by adding the following two properties: /** * The button's command, which is invoked whenever the button is fired. * If a command is set on the button, {@link Node#disableProperty()} is automatically * bound to {@link Command#canExecuteProperty()}. Any previous binding is removed. */ ObjectProperty<Command<?>> commandProperty(); /** * The button's command parameter. * When the command is invoked, this parameter will be passed to the command implementation. */ ObjectProperty<Object> commandParameterProperty(); These two properties are lazily instantiated to prevent allocations if an application doesn't use commands. In general, Commands are an opt-in feature, so existing code that makes no use of commands is not impacted. The command is invoked whenever the control fires an ActionEvent. This can be achieved by overriding Node.fireEvent(Event) in ButtonBase and checking for the presence of an ActionEvent. I can provide a PR with an implementation of this feature. Michael