Add a new stage style that extends the client area across the entire window, allowing JavaFX applications to place scene graph nodes everywhere and create custom client-side header bars with the javafx.scene.layout.HeaderBar layout container. It has three areas that accept child nodes: leading, center, and trailing. HeaderBar automatically adjusts for the placement of the default window buttons (iconify, maximize, close) on the left or right side of the window.
It is not a goal to:
- Only provide a better version of an
UNDECORATEDstage style without window buttons (iconify, maximize, close). Almost all applications will want to have window buttons that correspond to the OS, and only a tiny minority will want to fully customize even the window buttons. - Provide an API to control the basic appearance of platform windows. Applications will have no control over aspects like rounded vs. non-rounded corners, resize borders, and so on.
- Provide built-in tools to respond to light/dark modes of the OS, or stylistic changes for focused/unfocused windows. Applications can already to this on their own with the
Platform.PreferencesAPI.
Many modern applications use a customized title bar area to achieve a cohesive look and feel, without the classic separation between client area and non-client title bar. Here are some examples:
Notice how these applications take control of the title bar area by using interactive controls with application-specific styling.
This feature needs to be designed for JavaFX with various constraints in mind:
-
Multi-platform
Since JavaFX is a multi-platform framework, this feature must work out of the box on all supported platforms. It is a non-starter to require application developers to add platform-specific code to their applications if they want to use this feature. -
Ease of use
It must be easy to use. In particular, this means that default window interactions must work reliably and feel at home on the OS. If possible, we will use platform-native window buttons (iconify, maximize, close) instead of crafting our own bespoke versions.
Window buttons require quite a bit of effort to get it just right. It's way more effort than just throwing a bunch of buttons in the window corner and calling it a day. Window buttons need to interact with the OS in very specific ways to enable features like snap layouts, right-to-left locales, and other aspects. -
Customizability
All of the application examples given earlier use window buttons that are not gratuitously different than the platform-native window buttons; they feel at home on the target OS. This is why we provide platform-specific default window buttons. Application developers who need to customize window buttons can opt out of the default window buttons, and create their own buttons in the JavaFX scene graph.
-
EXTENDEDis likeUNDECORATEDin the following ways: The application controls the entirety of the window. There is no non-client area (i.e. no title bar), and scene graph nodes can be placed everywhere. Since there is no non-client title bar, applications will have to provide their ownHeaderBarand their own system menu (if they so desire). -
EXTENDEDis likeDECORATEDin the following ways: The window has a resize border, shadows, and window animations. It has the platform window buttons (minimize, maximize, close) superimposed over the application window. Just as with a decorated window, applications have no control over whether corners are rounded, how borders look like, and so on.
The EXTENDED style is a conditional feature that is available on Windows, macOS, and Linux, and it automatically downgrades to DECORATED on all other platforms.
| Feature | Windows | macOS | Linux | Android/iOS |
|---|---|---|---|---|
| Default window buttons | provided by JavaFX | native | provided by JavaFX | n/a |
| Resize border | outside, native | outside, native | inside, implemented in glass-gtk | n/a |
| Drop shadows | yes | yes | yes | n/a |
| Rounded corners | yes | yes | needs investigation | n/a |
| Click-and-drag to move | yes, with HeaderBar | n/a | ||
Double-click on HeaderBar | maximize | maximize/minimize/nothing, depending on system settings | maximize | n/a |
| Right-click to invoke system menu | yes, with HeaderBar | no | yes, with HeaderBar | n/a |
| Window title | needs to be provided by application | n/a | ||
The default window buttons are superimposed over the application window, and are not part of the JavaFX scene graph. On macOS, we can simply ask the operating system to do this for us. On Windows and Linux/GTK, there is no such option, which is why we need to do this within JavaFX.
The preferred height of the default window buttons can be specified with HeaderBar.setPrefButtonHeight(Stage, double). The platform implementation tries to accommodate the preferred height in various ways, such as by stretching the window buttons (fully or partially) to fill the preferred height, or centering the window buttons (fully or partially) within the preferred height.
The color scheme of the default window buttons automatically adapts to the background of the Scene (more precisely, the Scene.fill property) to remain easily recognizable. Application developers need to set the scene background to a value that corrsponds to the overall brightness of their application, independent of whether the scene background is visible or obscured by other controls.
Applications can opt out of default window buttons by setting the stage's preferred window button height to zero by calling HeaderBar.setPrefButtonHeight(Stage, double), and provide their own custom buttons in the JavaFX scene graph. In order to integrate custom buttons with the platform window manager, applications need to set HeaderBar.setButtonType(Node, HeaderButtonType) on each button, where HeaderButtonType is defined as follows:
public enum javafx.scene.layout.HeaderButtonType {
ICONIFY, MAXIMIZE, CLOSE
}With the absence of a system-provided header bar, the click-to-drag and double-click to maximize behaviors are lost with the removal of the system-provided header bar. Applications need to provide their own client-side header bar to get these window behaviors back.
The appearance of the client-side header bar (colors, dark/light theme, etc.) is left to the purview of application developers. The client-side header bar is a control just like any other JavaFX control, and application developers will decide how it looks like. Notably, there is no translucency, because JavaFX does not support window-level translucency yet.
HeaderBar allows applications to create an entirely custom header bar control. It can be any size, since it is just a regular resizable region in the JavaFX scene graph. It enables the click-to-drag and double-click to maximize behaviors that are usually provided by the system title bar.
The background of a header bar is draggable by default, but its content is not. Applications can further customize the draggable content with the HeaderBar.setDragType(Node, HeaderDragType) static method. HeaderDragType is defined as follows:
public enum javafx.scene.layout.HeaderDragType {
DRAGGABLE, // Marks a single node as draggable
DRAGGABLE_SUBTREE, // Marks a node and all of its descendants as draggable
NONE // Cancels an inherited DRAGGABLE_SUBTREE flag
}HeaderBar also defines two read-only properties: leftSystemInset and rightSystemInset of type Dimension2D, which correspond to the size of the system-reserved areas for window buttons. These areas refer to the physical top left and top right corners of the window, not adjusted for layout orientation (left-to-right/right-to-left). Applications should not place nodes in these areas, as the window buttons will be superimposed over the application window. If HeaderBar is used with a stage style other than EXTENDED (or if it was downgraded to DECORATED), the system-reserved areas will be empty (i.e. Dimension2D(0, 0)).
HeaderBar defines three areas in which scene graph nodes can be placed: leading, center, and trailing. For left-to-right locales, leading corresponds to the left side of the window and trailing corresponds to the right side; on right-to-left locales, the directionality is switched. The layout direction can be configured with Node.setNodeOrientation.
HeaderBar automatically adjusts for the presence of superimposed platform window buttons on the left or right side of the window, and ensures that its child nodes are appropriately shifted to the left or to the right.
All children of HeaderBar will be resized to their preferred widths and extend the height of the HeaderBar. It honors the minimum, preferred, and maximum sizes of its children. If a child's resizable range prevents it from be resized to fit within its available space, it will be vertically centered relative to the available space. The alignment can be further customized with layout constraints:
| Constraint | Type | Description |
|---|---|---|
| alignment | javafx.geometry.Pos | The alignment of the child within its area of the HeaderBar. |
| margin | javafx.geometry.Insets | Margin space around the outside of the child. |
When a node is placed in the center area, and its alignment is set to Pos.CENTER, Pos.TOP_CENTER, or Pos.BOTTOM_CENTER, a special layout algorithm is applied:
The node is not centered with respect to the center of its layout area, but with respect to the center of the window.
There is a good reason for it: Suppose an application wants to place a control in the center of the header bar (for example, a search text field). HeaderBar automatically adjusts for the presence of superimposed platform window buttons by shifting the header bar content either to the left or to the right (depending on the platform and on layout directionality). However, this would also move the text field that was supposed to be centered in the window slightly off-center. This layout algorithm corrects that and ensures that a centered node in the center area remains centered with respect to the window.
Compare the same application, running on Windows and macOS, and observe the difference between the purple leading, center, and trailing areas, as well as the layout of child nodes within those areas:

Note that HeaderBar respects the minimium, preferred, and maximum sizes of its child nodes, so the centering algorithm will eventually shift the centered node off-center if the layout constraints cannot be satisfied in the available space. Compare the next example, in which the text field is wider than before and the layout is overconstrained. The text field is shifted off-center:

This is a minimal example that uses a HeaderBar with a TextField in the center area. HeaderBar is usually placed in the top area of a BorderPane root container:
public class MyApp extends Application {
@Override
public void start(Stage stage) {
var headerBar = new HeaderBar();
headerBar.setCenter(new TextField());
var root = new BorderPane();
root.setTop(headerBar);
stage.setScene(new Scene(root));
stage.initStyle(StageStyle.EXTENDED);
stage.show();
}
}The integrated look-and-feel of an extended stage with client-side title bar requires intricate interactions with the native platform toolkits, and can only be done in JavaFX.
An alternative implementation might be to provide a window that is very similar to the proposed EXTENDED style, but without the superimposed window buttons. However, window buttons are surprisingly hard to get right. This would necessitate additional APIs to integrate user-provided window buttons with OS features like snap layouts.








It seems that when we use
stage.initStyle(StageStyle.EXTENDED)with RTL stage in Windows, the default buttons on the title bar are not rendered properly:https://www.youtube.com/watch?v=hoZRQ8Hl-6s