JavaFX Controls, Layouts & FXML

Layout Panes: BorderPane & GridPane

18 min Lesson 4 of 12

Layout Panes: BorderPane & GridPane

Two of the most powerful layout containers in JavaFX model the patterns that experienced UI developers reach for first: BorderPane for the classic chrome-plus-content shell, and GridPane for precise row-and-column positioning. Master these two and you can express the vast majority of real application layouts.

BorderPane — Region-Based Layout

BorderPane divides its space into five named regions: top, bottom, left, right, and center. You assign any Node to any region; unused regions collapse to zero. The center expands to fill all remaining space, making it the natural home for your main content area.

Why BorderPane matters: Every desktop application shell follows the same template — toolbar at the top, status bar at the bottom, navigation drawer on the left, properties panel on the right, and a canvas or list in the center. BorderPane encodes that template directly. You describe intent, not pixel arithmetic.

Here is a complete shell that looks like a typical IDE or file manager:

import javafx.application.Application; import javafx.geometry.Insets; import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.layout.*; import javafx.stage.Stage; public class BorderPaneDemo extends Application { @Override public void start(Stage stage) { BorderPane root = new BorderPane(); // ── TOP: a simple toolbar ───────────────────────────────────── ToolBar toolbar = new ToolBar( new Button("New"), new Button("Open"), new Separator(), new Button("Save") ); root.setTop(toolbar); // ── BOTTOM: status bar ──────────────────────────────────────── Label status = new Label("Ready"); status.setPadding(new Insets(4, 8, 4, 8)); root.setBottom(status); // ── LEFT: navigation tree ───────────────────────────────────── TreeView<String> nav = new TreeView<>( new TreeItem<>("Project") {{ getChildren().addAll( new TreeItem<>("src"), new TreeItem<>("resources"), new TreeItem<>("tests") ); setExpanded(true); }} ); nav.setPrefWidth(180); root.setLeft(nav); // ── RIGHT: properties panel ─────────────────────────────────── VBox props = new VBox(8, new Label("Properties"), new CheckBox("Read-only"), new CheckBox("Executable") ); props.setPadding(new Insets(8)); props.setPrefWidth(160); root.setRight(props); // ── CENTER: main content (fills remaining space) ────────────── TextArea editor = new TextArea("// start coding here…"); root.setCenter(editor); stage.setScene(new Scene(root, 800, 500)); stage.setTitle("BorderPane Demo"); stage.show(); } }

Alignment Inside BorderPane Regions

Each region slots one node. You control how that node sits inside the region with static helper methods defined on BorderPane:

// Align status label to the right edge of the bottom region BorderPane.setAlignment(status, javafx.geometry.Pos.CENTER_RIGHT); // Add padding between the node and the region edge BorderPane.setMargin(nav, new Insets(4));
Nest when you need multiple children in one region. A region holds exactly one node, but that node can be an HBox, VBox, or any other pane containing as many children as you like. This is the normal pattern — never fight the single-child contract.

GridPane — Row-and-Column Layout

GridPane arranges children in a grid of cells. Unlike HTML tables, cells have no default borders and can be any size — each row and column sizes independently to its largest content (or to explicit constraints you provide). Children can span multiple rows and columns.

You place each child by calling add(node, columnIndex, rowIndex) or the span overload add(node, col, row, colSpan, rowSpan). Indices start at zero.

import javafx.application.Application; import javafx.geometry.*; import javafx.scene.Scene; import javafx.scene.control.*; import javafx.scene.layout.*; import javafx.stage.Stage; public class GridPaneDemo extends Application { @Override public void start(Stage stage) { GridPane grid = new GridPane(); grid.setHgap(10); // horizontal gap between columns grid.setVgap(8); // vertical gap between rows grid.setPadding(new Insets(16)); // Row 0 — First name grid.add(new Label("First name:"), 0, 0); grid.add(new TextField(), 1, 0); // Row 1 — Last name grid.add(new Label("Last name:"), 0, 1); grid.add(new TextField(), 1, 1); // Row 2 — Email grid.add(new Label("Email:"), 0, 2); grid.add(new TextField(), 1, 2); // Row 3 — Multi-line notes field spanning both columns grid.add(new Label("Notes:"), 0, 3); TextArea notes = new TextArea(); notes.setPrefRowCount(4); grid.add(notes, 1, 3, 1, 2); // spans 1 col, 2 rows // Row 5 — Submit button spanning the full width Button submit = new Button("Submit"); GridPane.setColumnSpan(submit, 2); GridPane.setHalignment(submit, HPos.RIGHT); grid.add(submit, 0, 5); stage.setScene(new Scene(grid, 400, 320)); stage.setTitle("GridPane Demo"); stage.show(); } }

Column and Row Constraints

By default, columns shrink to their minimum content width. For forms you usually want the label column to stay tight and the input column to grow with the window. Use ColumnConstraints:

ColumnConstraints labelCol = new ColumnConstraints(); labelCol.setMinWidth(90); labelCol.setHgrow(Priority.NEVER); ColumnConstraints fieldCol = new ColumnConstraints(); fieldCol.setHgrow(Priority.ALWAYS); // expand to fill available width fieldCol.setFillWidth(true); grid.getColumnConstraints().addAll(labelCol, fieldCol);

The equivalent for rows is RowConstraints — you can fix a row height with setMinHeight / setPrefHeight or let it grow with setVgrow(Priority.ALWAYS).

Aligning Content Within a Cell

Two static methods control a node's position inside its cell:

  • GridPane.setHalignment(node, HPos.CENTER) — horizontal alignment: LEFT, CENTER, RIGHT.
  • GridPane.setValignment(node, VPos.TOP) — vertical alignment: TOP, CENTER, BOTTOM, BASELINE.
  • GridPane.setMargin(node, new Insets(...)) — spacing around a specific node.
  • GridPane.setFillWidth(node, true) — stretch the node to fill the cell width.
Do not place two nodes in the same cell. JavaFX does not throw an error — it silently stacks them. If a label appears to vanish, check for accidental same-cell overlap before anything else.

Combining BorderPane and GridPane

In practice you rarely choose one over the other — you nest them. A typical registration screen uses BorderPane as the top-level root (toolbar, status bar, padded center) with a GridPane as the center child containing the form fields. The BorderPane handles the overall application shell; the GridPane handles the internal form alignment. Each pane does what it is designed for, and neither fights the other.

Summary

BorderPane gives you the five-region shell pattern: top, bottom, left, right, and an expanding center — perfect for application chrome. GridPane gives you row-and-column precision with spanning, gap control, and per-column grow policies — perfect for data entry forms. Nest them freely: the outer BorderPane defines the application skeleton; inner GridPanes (or HBox/VBox) build the detail panels. Together these two panes cover the bulk of professional desktop application layouts.