In this tutorial, you’ll learn how to use CSS (Cascading Style Sheets) to customize the look and feel of your JavaFX application.

You can use CSS in JavaFX applications similar to how you use CSS in HTML. You should have a basic understanding of CSS to get the most out of this tutorial.

Following is the screenshot of the application that we’ll build in this tutorial -

Default CSS for JavaFX applications

The default css for all JavaFX applications is written in a file called modena.css, which can be found in the JavaFX runtime jar file, jfxt.jar, located in your Java installation folder. This css file defines the styles for the root node and the UI controls.

To view the contents of the default css, go to your JDK installation directory, then go to jre/lib/ext folder, and extract the stylesheet from jfxt.jar.

The file modena.css is located under com/sun/javafx/scene/control/skin/modena directory -

$ cd $JAVA_HOME/jre/lib/ext

$ sudo jar xf jfxrt.jar com/sun/javafx/scene/control/skin/modena/modena.css

$ vi com/sun/javafx/scene/control/skin/modena/modena.css

The default css is always applied to every JavaFX application. However, you can create one or more custom stylesheets of your own and add them to your application to override the default styles defined by JavaFX.

Creating the Project

Let’s create a demo project to learn how to style JavaFX applications. Fire up your favourite IDE and create a new Java project. Now, create the following files in src folder under a package named javafx.example-

  • CSSDemoApplication.java - This is the main class of your JavaFX application.
  • css_demo.fxml - This is the FXML source file where you define the user interface.
  • demo.css - This is the CSS file in which you define the styles for ui elements.

The project’s directory structure looks like this -

javafx-css-demo-app
    └── src
         └── javafx
               └── example
                     └── CSSDemoApplication.java
                     └── css_demo.fxml
                     └── demo.css

Creating the Main Application Class

For creating a new JavaFX application, you need to create a class, extend it from javafx.application.Application and override it’s start() method.

Checkout my JavaFX Beginners tutorial for learning more about a typical JavaFX application and it’s life cycle.

Let’s create the Main class for our JavaFX application. Open CSSDemoApplication.java file and add the following code to it -

package javafx.example

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class CSSDemoApplication extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("css_demo.fxml"));
        Scene scene = new Scene(root, 800, 500);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

In the start() method, we load the FXML document, create a scene with the root node found from FXML and set the scene in primary stage.

Creating the layout of the application

Next step is to create the layout of your application in the FXML source file, css_demo.fxml.

I’ll not go into the details of the FXML layout. Checkout my tutorial on How to design JavaFX layouts using FXML for learning more about FXML.

In this article we’ll be focusing on CSS. Just add the following XML to your css_demo.fxml file -

<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.image.ImageView?>
<?import javafx.scene.image.Image?>
<BorderPane>
    <top>
        <BorderPane styleClass="header-section">
            <left>
                <Label id="header-text" text="Application Header"></Label>
            </left>
            <right>
                <Button id="account" text="Account">
                    <graphic>
                        <ImageView fitHeight="24" fitWidth="24" 
                            pickOnBounds="true" preserveRatio="true">
                            <image>
                                <Image url="@javafx_account_example.png" />
                            </image>
                        </ImageView>
                    </graphic>
                </Button>
            </right>
        </BorderPane>
    </top>
    <left>
        <VBox styleClass="sidebar-section">
            <children>
                <Label text="Sidebar Item1"></Label>
                <Label text="Sidebar Item2"></Label>
                <Label text="Sidebar Item3"></Label>
                <Label text="Sidebar Item4"></Label>
            </children>
        </VBox>
    </left>
    <center>
        <VBox styleClass="content-section">
            <children>
                <Label id="content-header" text="Content header"></Label>
                <Label id="content">
                    <text>
                        Lorem Ipsum is simply dummy text of the printing and
                        typesetting industry. Lorem Ipsum has been the industry's
                        standard dummy text ever since the 1500s, when an unknown 
                        printer took a galley of type and scrambled it to make a 
                        type specimen book. It has survived not only five centuries, 
                        but also the leap into electronic typesetting, remaining 
                        essentially unchanged. It was popularised in the 1960s with 
                        the release of Letraset sheets containing Lorem Ipsum 
                        passages, and more recently with desktop publishing software 
                        like Aldus PageMaker including versions of Lorem Ipsum.
                    </text>
                </Label>
            </children>
        </VBox>
    </center>
    <bottom>
        <HBox id="footer-section">
            <children>
                <Label text="Copyright 2017 CalliCoder"></Label>
            </children>
        </HBox>
    </bottom>
</BorderPane>

Note that, the above FXML also contains an image. Click here to download the image and save it in the same folder where your FXML file resides.

Creating and Adding stylesheets to the Application

If you run the application right now, it’ll look ugly! No, Seriously It’ll look ugly!

Let’s style the application by adding css. We’ll first add the CSS and run the application, and then learn how the styles specified in the css file relate to the UI elements.

Open demo.css file and add the following css -

.root {
    -fx-font-size: 14px;
    -fx-font-family: sans-serif;
    -fx-background-color: #ffffff;
}

.header-section {
    -fx-padding: 10px;
    -fx-font-size: 20px;
    -fx-background-color: teal;
}

.header-section Label {
    -fx-text-fill: #ffffff;
    -fx-padding: 10px;
}

#account {
    -fx-background-color: transparent;
    -fx-text-fill: #ffffff;
    -fx-font-size: 16px;
    -fx-cursor: hand;
}

.sidebar-section {
    -fx-min-width: 200px;
    -fx-pref-width: 200px;
    -fx-max-width: 200px;
    -fx-border-width: 1;
    -fx-border-color: transparent #E8E8E8 transparent transparent;
}

.sidebar-section Label {
    -fx-font-size: 18px;
    -fx-padding: 10 15 10 15;
    -fx-border-width: 1;
    -fx-border-color: transparent transparent #E8E8E8 transparent;
    -fx-min-width: 200px;
    -fx-pref-width: 200px;
    -fx-max-width: 200px;
}

.content-section {
    -fx-padding: 10 20 10 20;
    -fx-wrap-text: true;

}

#content-header {
    -fx-font-size: 18px;
    -fx-padding: 0 0 10 0;
    -fx-font-weight: 700;
}

#content {
    -fx-wrap-text: true;
    -fx-font-size: 16px;
}

#footer-section {
    -fx-alignment: center;
    -fx-padding: 10 10 10 10;
    -fx-border-width: 1;
    -fx-border-color: #E8E8E8 transparent transparent transparent;
}

Now that we have created the CSS file, let’s add the css to our application. There are two ways in which you can add a stylesheet to your JavaFX application -

1. Adding stylesheet through Java code

Use the code shown below to add the stylesheet, demo.css to the JavaFX Scene. Note that it looks for demo.css file in the same directory in which the main application class resides.

scene.getStylesheets().add(getClass().getResource("demo.css").toExternalForm());

2. Adding stylesheet through FXML

Add a stylesheets element before the end of the root layout element in your FXML. In our case, the root layout element is BorderPane. Just add the following snippet before the closing </BorderPane> element

<stylesheets>
    <URL value="@demo.css" />
</stylesheets>

The @ symbol before the name of the css file in the URL indicates that the style sheet is in the same directory as the FXML file.

That’s it! You can now run the application, it’ll pick the styles from the css file and style the ui elements.

All the JavaFX CSS definitions contain a Selector and one or more JavaFX properties and their values. JavaFX property names are prefixed by -fx-. Property names and values are separated by colons (:), and multiple style declarations are separated by a semicolon.

JavaFX CSS Definition

Selectors

Selectors are used to identify the ui elements to which the style has to be applied. Each CSS style definition specifies a Selector and one or more styles separated by a semicolon. -

/* CSS selector and styles */
.header-section {
    -fx-padding: 10px;
    -fx-font-size: 20px;
    -fx-background-color: teal;
}

Selectors “find” the JavaFX elements based on their element name, id or styleClass. Following are different types of Selectors -

  1. Element Name Selectors -

    Element Name Selectors select all elements in FXML with that name. For example, the selector, Label will select all labels in the FXML document.

     Label
     Button
     GridPane
    
  2. Style Class Selectors -

    Style class selectors are preceded by a dot (.). You can add one style class to multiple JavaFX elements. The styles defined for a class will be applied to all the elements that has the specified class.

    You can add a styleClass to an element in FXML by using styleClass attribute.

     <!-- Adding style class in FXML -->
     <BorderPane styleClass="header-section">
    

    Also, if you’ve created the ui element thorough java code, you can add the style class using -

     node.getStyleClass().add("header-section")
    

    Following are some examples of style class selectors -

     .header-section
     .sidebar-section
     .content-section
    
  3. ID Selectors -

    You can also define styles by using a node’s id. ID selectors are preceded by # symbol. Unlike style classes, id is unique to an element.

    A node’s id can be set using id attribute in FXML, and using setId() method in java.

    Following are some examples of ID selectors -

     #account
     #footer-section
     #content    
    

Compound Selectors

You can also use compound selectors in your style definitions like the one below -

.header-section Label

The example above selects all the Label elements that are descendant of elements with header-section class.

Pseudo Selectors

JavaFX also supports selectors for pseudo-classes. For example -

.button:focused
.button:hover

Root Style class

The .root style class is applied to the root node of the Scene instance. It’s similar to the body element in html. Since all nodes in a scene are descendant of the root node, styles in the .root class are applied to all the nodes. .root class can be used to define default values for font-size, font-family etc. to provide consistency in the UI.

Conclusion

In this blog post, We learned how to create and add css to JavaFX applications and explored different css concepts through simple examples. You can find the code for the demo application that we built in this tutorial on my github repository.

For more information on this subject, see the Oracle JavaFX CSS Reference Guide. Thank you for reading. I hope you liked the post. Please ask any questions in the comment section below.