Introduction to FXML
Introduction to FXML
So far in this tutorial you have built every UI in pure Java: you created nodes, set properties, added children, and wired listeners all inside the same class. This works for small examples, but it quickly becomes unmanageable. A 200-line start() method that mixes layout logic with business logic is difficult to read, impossible to hand to a designer, and a nightmare to test.
FXML is JavaFX's answer to this problem. It is an XML-based markup language that lets you declare your user interface in a separate file, completely independent of the Java code that drives it. Think of it as the JavaFX equivalent of HTML for web pages: the markup describes structure, the Java class handles behaviour.
Why FXML Exists
There are three concrete benefits that motivate every professional JavaFX project to use FXML:
- Separation of concerns — the layout file (
.fxml) is purely structural. A designer or a tooling assistant can edit it without touching a single Java class. - Tooling support — Scene Builder, the drag-and-drop GUI designer, reads and writes FXML natively. You drag a
Buttononto the canvas and Scene Builder writes the XML for you. - Readability — a deeply nested layout that takes 80 Java lines becomes 30 lines of indented XML, and the hierarchy is visually obvious.
FXMLLoader, which parses the XML, instantiates the nodes, sets property values, and injects them into a controller class you provide. This means you can update the layout without recompiling your Java code — very useful during UI iteration.
Anatomy of an FXML File
An FXML file is a standard XML document. The root element is almost always a layout pane or a container node. Attributes map directly to JavaFX node properties. Here is the simplest possible example — a VBox holding a Label and a Button:
A few things to notice:
<?import ...?>processing instructions work exactly like Java import statements. Every class you reference in the markup must be imported this way.xmlns:fx="http://javafx.com/fxml"declares thefx:namespace, which gives access to special FXML attributes likefx:idandfx:controller.fx:controllertellsFXMLLoaderwhich Java class is the controller for this file. The loader will instantiate it automatically.onAction="#handleClick"— the#prefix means "look up a method namedhandleClickon the controller".
Loading FXML with FXMLLoader
The bridge between your FXML file and your running application is javafx.fxml.FXMLLoader. You call it once in Application.start():
loader.load() returns the root node of the scene graph declared in the FXML file — in this case a VBox. The return type is usually cast to Parent or the concrete type, whichever you need.
src/main/resources (Maven/Gradle layout), in a package that mirrors your Java source tree. For example, if your controller is com.example.HelloController, place the FXML at src/main/resources/fxml/hello.fxml and load it with getClass().getResource("/fxml/hello.fxml"). Keeping them on the classpath — not the filesystem — means the path works identically in your IDE, in a fat JAR, and in a native image.
Setting Properties in FXML
Any JavaFX property that has a public setter can be set as an XML attribute. Primitive types are coerced automatically; colours and enums are looked up from their string representations. Complex objects are expressed as nested child elements:
The fx:id attribute is special: it tells FXMLLoader to inject this node into a matching @FXML-annotated field in the controller. That connection is the topic of the next lesson; for now just know the naming convention: fx:id must match the Java field name exactly.
The FXML Namespace and Special Attributes
The fx: namespace provides a small set of powerful attributes:
fx:id— names a node so the controller can reference it.fx:controller— specifies the controller class (set once on the root element).fx:include— embeds another FXML file, enabling modular layouts.fx:define— declares objects outside the scene graph (useful for shared resources).fx:root— enables the custom component pattern where a class IS both the root node and its own controller.
Static vs Property Element Syntax
JavaFX FXML supports two syntaxes for setting values. The attribute syntax is concise and works for strings and simple types:
The property element syntax is used for values that are objects themselves, such as Insets, Font, or ObservableList:
You will see both forms used together in real FXML files. Prefer attribute syntax when it reads clearly; fall back to element syntax for complex object graphs.
getResource() path. If the path starts with / it is absolute from the classpath root. Without the leading slash it is relative to the calling class's package directory. A wrong path causes FXMLLoader.load() to throw a NullPointerException at runtime — not a compile error — so always verify the file is actually on the classpath and the path string is correct.
A Minimal Working Project Structure
A typical Maven project with FXML looks like this:
The Maven build copies everything under resources/ to the classpath root, so getClass().getResource("/fxml/hello.fxml") resolves correctly at runtime.
Summary
FXML separates your UI declaration from your application logic by expressing the scene graph as XML. You import classes with <?import?>, bind a controller with fx:controller, name nodes with fx:id, and wire event handlers with #methodName. FXMLLoader bridges the markup and the Java runtime: it parses the file, builds the node tree, and hands back the root node ready to be placed in a Scene. This clean separation is the foundation of every professional JavaFX application — and Scene Builder, the drag-and-drop visual editor, works entirely on top of it.