Equo Chromium: Embedded Browser as a JavaFX Node
Axel Orsingher on september 25th 2026
JavaFX gives you a clean scene graph, hardware-accelerated rendering, and a coherent component model — but until now, embedding a real browser inside it required awkward workarounds: spawning a separate process, marshaling frames over sockets, or dropping down to OS-level APIs to paste a native window into the JavaFX hierarchy. None of those approaches actually integrate with the scene graph. They don't obey layout, they don't clip, and they certainly don't handle HiDPI correctly.
Equo Chromium now ships a JavaFX mode that changes that. The browser runs offscreen (OSR) inside CEF, delivers BGRA pixel frames to a WritableImage, and shows up in your scene graph as a plain javafx.scene.Node. Layout, clipping, and HiDPI all work because the browser really is a node — not a foreign window pasted on top.
One Call to Embed Chromium
The public API is a single static factory on ChromiumBrowser:
StackPane browserHost = new StackPane();
ChromiumBrowser browser = ChromiumBrowser.javafx(browserHost, "https://equo.dev");
Pass any javafx.scene.layout.Pane and a URL. That's it. The node is added to the pane immediately and starts rendering as soon as CEF delivers the first frame. From that point forward, the browser is just another child node — you can put it in a BorderPane, stack things on top of it, animate it, or bind its size to anything in your scene.
The same one-liner works in Kotlin:
val browserHost = StackPane()
val browser = ChromiumBrowser.javafx(browserHost, "https://equo.dev")
The Scene Graph Stays in Charge
Because the browser is a real node, layout works exactly as you'd expect. The sample app puts the browser in the center of a BorderPane, under a toolbar made of plain JavaFX controls:
BorderPane root = new BorderPane();
root.setTop(toolbar); // a real JavaFX HBox
root.setCenter(browserHost); // the browser node
The browser listens to its own layout bounds. When the pane resizes, it reports the new logical size back to CEF, which re-renders at that exact size. Device scale factor is read from Window.getRenderScaleX(), so HiDPI screens get native-resolution frames automatically; no manual scaling, no blurry rendering on 4K displays.
Screen position is tracked the same way: localToScreen(0, 0) keeps CEF informed, which matters for OSR popups (like <select> dropdowns) that need absolute coordinates to appear in the right place.
Input Feels Native
Mouse clicks, drags, scrolls, and keystrokes are translated from JavaFX events and forwarded directly to the offscreen CEF browser. All the modifiers you'd expect — Shift, Ctrl, Alt, Meta — come through correctly. Scroll follows the JavaFX delta directly rather than forcing a fixed notch-per-event model.
Focus is wired to JavaFX focus: when the node gains focus, CEF activates; when it loses focus, CEF deactivates. Right-click opens a proper JavaFX ContextMenu (since OSR can't draw CEF's native popup menu).
Popups Open as JavaFX Stages
window.open() and target=_blank links work out of the box. CEF's native popup mechanism can't create a visible window in OSR mode, so Equo Chromium intercepts the before-popup event and opens a new javafx.stage.Stage with its own browser inside:
subscribe().onBeforePopup(event -> {
event.prevent();
Platform.runLater(() -> openPopupWindow(event.getUrl()));
});
The popup window tracks the page title via onTitleChanged, so it behaves the way users expect, just like Chrome opening a new tab in a new window.
The Full Equo Chromium API, Unchanged
JavaFX mode supports the same ChromiumBrowser API you'd use in SWT, Swing, or Standalone:
browser.setUrl("https://example.com");
browser.executeJavaScript("document.title = 'hello'");
browser.showDevTools();
browser.subscribe().onTitleChanged(e -> stage.setTitle(e.getTitle()));
browser.printToPdf("/tmp/page.pdf", settings -> {});
Every event subscription, every navigation method, DevTools, PDF printing, all available without modification. The toolkit abstraction stays intact; only the rendering surface changes.
Get Started
Maven (Java):
<dependency>
<groupId>com.equo</groupId>
<artifactId>chromium</artifactId>
<version><!-- latest --></version>
</dependency>
//mvn verify # runs the sample; override with -Durl=https://...
Gradle (Kotlin):
./gradlew :app:run # override with -Durl=https://...
Both sample projects are in the chromium.samples repository under maven-samples/javafx and gradle-samples/javafx.
Why This Matters
Embedding a real browser into a native UI toolkit has always meant fighting the windowing system. SWT's Browser widget hosts a native CEF window as a child of the SWT composite. Swing's mode wraps the CEF component in an AWT hierarchy. Both approaches depend on the OS window manager to handle painting, sizing, and Z-order.
JavaFX mode flips that: CEF never creates a window. Instead, it renders into a pixel buffer, and the JavaFX scene graph decides what to do with those pixels. The result is a browser that behaves like a node, because it is one.
If you're building a JavaFX application that needs to display web content, instrument it with Java logic, or expose a web-based UI alongside native controls, Equo Chromium's JavaFX mode is the missing piece.
To learn more about how Equo Chromium can provide modern web integrations for your application, visit our GitHub repository or contact us to discuss a modernization prototype.