JavaFX 25 Highlights

JavaFX 25 is here with several new features and improvements! JavaFX 25 is designed to work with JDK 25, and is known to work with JDK 23 and later versions. Here are the highlights of the JavaFX 25 release:

  • JavaFX controls in the title bar (Preview)
  • RichTextArea (Incubator) : CSS styling of highlights
  • CSS media feature queries
  • TabStopPolicy for TextFlow
  • Additional geometry-based Text / TextFlow APIs
  • Text Layout API

JavaFX Controls in the Title Bar (Preview)

This preview feature defines a Stage style in which the client area is extended into the header bar area, removing the separation between the two regions and allowing applications to place scene graph nodes in the header bar area of the Stage.

The new feature provides the default header buttons (iconify, maximize, close), but no system-provided draggable header bar. Applications provide their own header bar by placing a HeaderBar control in the scene graph, positioned at the top of the window. HeaderBar automatically adjusts for the placement of the default window buttons on the left or right side of the window.

Here is a simple example:

public class HeaderBarApp extends Application {
    @Override
    public void start(Stage stage) {
        var button = new Button("My button");
        HeaderBar.setAlignment(button, Pos.CENTER_LEFT);
        HeaderBar.setMargin(button, new Insets(5));

        var headerBar = new HeaderBar();
        headerBar.setCenter(button);

        var root = new BorderPane();
        root.setStyle("-fx-background: #afafbf;");
        root.setTop(headerBar);

        var scene = new Scene(root, 200, 150);
        scene.setFill(Color.web("afafbf"));
        stage.setScene(scene);
        stage.initStyle(StageStyle.EXTENDED);
        stage.show();
    }
}

This example produces the following results on Windows and macOS.

Extended Stage with HeaderBar on Windows
Figure 1: Extended Stage with HeaderBar on Windows

Extended Stage with HeaderBar on macOS
Figure 2: Extended Stage with HeaderBar on macOS

To try this preview feature you need to run the example with java -Djavafx.enablePreview=true ... on the command line.

RichTextArea (Incubator) : CSS Styling of Highlights

Applications can now style RichTextArea highlights using CSS. JavaFX 25 added new overloads for the following methods that take a list of CSS style names:

  • RichParagraph::addHighlight
  • RichParagraph::addWavyUnderline
  • SimpleViewOnlyStyledModel::highlight
  • SimpleViewOnlyStyledModel::addWavyUnderline

CSS Media Feature Queries

This feature adds media queries to JavaFX CSS, a powerful component that enables stylesheets to dynamically test specific aspects of the JavaFX scene. Media queries are independent of the contents of the scene graph, its styling, or any other internal aspect; they’re only dependent on the “external” configuration of the scene. The following example stylesheet uses a media query:

    .button {
        -fx-background-color: lightgray;
        -fx-text-fill: black;
    }

    @media (prefers-color-scheme: dark) {
        .button {
            -fx-background-color: darkgray;
            -fx-text-fill: white;
        }
    }

In the example above, the button’s background and foreground colors will change at runtime when the preferred color scheme is changed to dark. Since a media query can contain arbitrary CSS rules, all aspects of styling can be adjusted.

TabStopPolicy for TextFlow

TabStopPolicy provides a way for applications to define tab stops based on a geometric position in the text line rather than a fixed number of characters. This makes it suitable for both proportional and monospaced fonts while offering better support for rich text. Here is a code snippet showing how to add tab stops to your TextFlow:

    var str1 = "This is...\t";
    var str2 = "a test\tof tabs";
    TextFlow flow = createTextFlow(str1, str2);

    // Create tab stops
    var stops = List.of(
        new TabStop(25),
        new TabStop(90),
        new TabStop(180)
    );

    // Create tab stop policy
    var tsPolicy = new TabStopPolicy();
    tsPolicy.tabStops().addAll(stops);
    flow.setTabStopPolicy(tsPolicy);

And below you can observe the example output. The light green vertical lines were added to show where the tab stops are.

TabStopPolicy

Additional Geometry-Based Text / TextFlow APIs

JavaFX 25 added new geometry-based methods to Text and TextFlow. This was done to provide missing APIs as well as the ability to properly account for insets and padding in TextFlow.

Class Methods
Text getRangeShape, getStrikeThroughShape
TextFlow getHitInfo, getCaretShape, getRangeShape, getUnderlineShape, getStrikeThroughShape

Text Layout API

This feature provides a new LayoutInfo object that holds a snapshot of the text layout geometry in a Text or TextFlow node. This includes a list of text lines, shapes derived from the layout (for example, selection, underline, strike-through), and caret information.

For example:

    Text textNode = createTextNode();

    // Get the layout info for this text node and print the text lines
    var layoutInfo = textNode.getLayoutInfo();
    layoutInfo.getTextLines(false)
        .stream()
        .forEach(System.out::println);

Other Changes

Checkout the JavaFX 25 Release Notes for a complete list of important changes, new features, enhancements, and bug fixes. See also the API docs for a list of new APIs and deprecated APIs in each release.

Call to Action

We invite you to download JavaFX 25 today from jdk.java.net/javafx25 and use it to build and run your applications.

Please send feedback to openjfx-dev@openjdk.org (registration required). We especially welcome feedback on the JavaFX Preview API (controls in the title bar) and Incubating APIs (RichTextArea and InputMap), as we evolve those APIs towards finalization.