Rendering
The guide describes how different rendering modes work and explores their limitations.
Overview
The way JxBrowser renders web content inside BrowserView is determined by the rendering mode. There are two rendering
modes in JxBrowser: HARDWARE_ACCELERATED and OFF_SCREEN.
You specify the rendering mode when you create an Engine instance, and it can’t be changed later. All browsers
created within the Engine will use the same rendering mode.
import static com.teamdev.jxbrowser.engine.RenderingMode.HARDWARE_ACCELERATED;
...
var engine = Engine.newInstance(HARDWARE_ACCELERATED);
import com.teamdev.jxbrowser.engine.RenderingMode.HARDWARE_ACCELERATED
...
val engine = Engine(HARDWARE_ACCELERATED)
Choosing the right rendering mode affects:
- rendering performance,
- overall resource consumption,
- and the way JxBrowser handles user input.
When the GPU is available, Chromium uses hardware acceleration in both rendering modes. When the GPU is not available, Chromium switches to the CPU-bound software rendering — also in both rendering modes.
Hardware accelerated
In this rendering mode, Chromium renders the web content directly on a special rendering surface that
the library puts on top of BrowserView. The type of surface depends on the operating system.
Architecture of the HARDWARE_ACCELERATED rendering mode.
On Windows and Linux, JxBrowser embeds a native Chromium window into the Java application. This way, Chromium renders content in its own window with the same performance as a standalone browser. The embedded window is unobtrusive to the end user: it has no Chromium UI elements, taskbar icon, or other characteristics of a regular window.

The embedded window looks like any other UI component.
On macOS, JxBrowser creates a native CARemoteLayer surface that is shared between the Java and Chromium processes.
The surface is embedded into the Java window, and Chromium renders the content directly to the surface.
On macOS, a different approach is required because the operating system allows native windows to be re-parented only within the same process. Since JxBrowser launches Chromium in a separate process, the Chromium window cannot be attached to the Java window hierarchy as it can on Windows and Linux.
Input handling
On Windows and Linux, the input is handled by Chromium. Since the user interacts directly with the Chromium window, the OS sends keyboard, accessibility, and other input events there, bypassing the Java window. That ensures exactly the same reaction on input as in Google Chrome.
On macOS, the input is handled by Java UI toolkits. See the “Input handling” section in the off-screen mode for details.
You can intercept mouse, keyboard, and touch events in the Java code. Visit the Intercepting events guide to learn how.
Limitations
Overlapping with other UI components
Regardless of the operating system, the rendering surface for web content is always placed above the Java window.
As a result, regular UI components cannot appear over BrowserView because its area is obscured by
the rendering surface.
In particular, avoid using the HARDWARE_ACCELERATED rendering mode when adding BrowserView into JInternalFrame
or JLayeredPane in Swing, or StackPane in JavaFX.

Two BrowserView components — in different modes — overlapping with JPanel.
Transparent windows in JavaFX
In JavaFX on Windows, the HARDWARE_ACCELERATED rendering mode is not compatible with the
StageStyle.TRANSPARENT style. To show a transparent Stage, JavaFX uses
layered windows, but this approach doesn’t
work with the embedded Chromium window.
Off-screen
In this rendering mode, Chromium renders content on the GPU. Then, the library copies
pixels into an off-screen buffer in the Java process memory. The BrowserView acts as a lightweight component that
reads pixels from the buffer and displays them using standard UI toolkit graphics, such as Graphics2D in Swing.
Architecture of the OFF_SCREEN rendering mode.
Input handling
By default, input events are handled by the Java window. When an input event occurs, the operating system dispatches
it to a Java UI toolkit, which passes it to BrowserView, which forwards it to Chromium, which delivers it
to the web page.
Limitations
Native input handling
At every stage of event handling, the event is converted from one data structure to another. Because data structures in different subsystems don’t match exactly, the data may be lost or misinterpreted. That creates rare cases in which a user interaction in JxBrowser produces a different JavaScript event than the same interaction in Chromium.
In JxBrowser 7.39.0, we introduced an experimental feature that directly forwards input events from the operating system to Chromium. This way, the JavaScript events generated in JxBrowser always match those in Chromium.
To activate the feature, use the system property:
System.setProperty("jxbrowser.native.input.enabled", "true");
Touch events
Swing, JavaFX, SWT, and Compose lack full touch support. As a result, some Chromium gestures, such as pinch-to-zoom, don’t work in JxBrowser — in OFF_SCREEN mode on Windows and Linux, and in both modes on macOS.
Performance
In the HARDWARE_ACCELERATED mode, the GPU usage directly affects rendering performance since Chromium renders content
directly on the surface. This mode provides the same rendering performance as standalone Google Chrome. On most
platforms, it can output 60 FPS for a 4K video.
In the OFF_SCREEN mode, using the GPU improves overall resource consumption, but doesn’t affect rendering
performance as much. In this mode, the limiting factor is copying pixels between processes, which is a CPU-bound
operation. This mode provides good rendering performance in most cases. For applications where
the rendering performance is critical, it’s better to use the HARDWARE_ACCELERATED mode.
Headless
When you don’t need to show the browser in the UI, prefer the HARDWARE_ACCELERATED rendering mode.
The reason is that the OFF_SCREEN mode may consume extra CPU and RAM even when the browser is not displayed.
Regardless of the rendering mode, JxBrowser remains fully functional outside of BrowserView. For example, you can
take a screenshot of a bare Browser in any rendering mode:
var engine = Engine.newInstance(HARDWARE_ACCELERATED);
var browser = engine.newBrowser();
browser.resize(1920, 1080);
browser.navigation().loadUrlAndWait("https://html5test.teamdev.com");
// Take the bitmap of the web page. Its size will be 1920x1080.
var bitmap = browser.bitmap();
import com.teamdev.jxbrowser.dsl.Engine
...
val engine = Engine(HARDWARE_ACCELERATED)
val browser = engine.newBrowser()
browser.resize(1920, 1080)
browser.navigation().loadUrlAndWait("https://html5test.teamdev.com")
// Take the bitmap of the web page. Its size will be 1920x1080.
val bitmap = browser.bitmap()