List icon Contents

Navigation

This guide describes the navigation events, and shows how to load URLs and files, filter navigation requests, work with navigation history, etc.

Loading URL

To navigate to a resource identified by a URL you can use one of the following methods:

  • Navigation.loadUrl(String url)
  • Navigation.loadUrl(LoadUrlParams params)

The following example shows how to navigate to https://www.google.com using the Navigation.loadUrl(String) method:

Java
Kotlin
Navigation navigation = browser.navigation();
navigation.loadUrl("https://www.google.com");
val navigation = browser.navigation()
navigation.loadUrl("https://www.google.com")

The code above requests navigation to the given resource and exits immediately. It does not wait until the resource is loaded completely.

If you need to block the current thread execution until the resource is loaded completely, use the Navigation.loadUrlAndWait(String url, Duration timeout) method:

Java
Kotlin
navigation.loadUrlAndWait("https://www.google.com", Duration.ofSeconds(45));
navigation.loadUrlAndWait("https://www.google.com", Duration.ofSeconds(45))

This method blocks the current thread execution until the main frame of the resource is loaded completely or until the given 45 seconds timeout is reached.

If navigation fails, the NavigationException exception will be thrown.

If the resource has not been loaded within a timeout, the TimeoutException exception will be thrown.

Loading URL with POST

To load a web page and send POST data, use the Navigation.loadUrl(LoadUrlParams) method. The following code demonstrates how to form the POST data send it to the URL.

Java
Kotlin
TextData data = TextData.of("post data");
LoadUrlParams params = LoadUrlParams.newBuilder(url)
        .uploadData(data)
        .addExtraHeader(HttpHeader.of("Content-Type", "text/plain"))
        .build();
navigation.loadUrl(params);
val data = TextData.of("post data")
val params = LoadUrlParams.newBuilder(url)
    .uploadData(data)
    .addExtraHeader(HttpHeader.of("Content-Type", "text/plain"))
    .build()
navigation.loadUrl(params)

Other types of POST data are also available: MultipartFormData, FormData, ByteData.

Loading file

You can use the same methods to load HTML files from the local file system. You just need to provide an absolute path to the HTML file instead of a URL.

For example:

Java
Kotlin
navigation.loadUrl(new File("index.html").getAbsolutePath());
navigation.loadUrl(File("index.html").absolutePath)

Loading HTML

This section describes how to load HTML in a Frame.

There are two possible approaches to do it:

  • By generating and loading Data URL.
  • By registering a Custom Scheme and intercepting specific URL requests.

These approaches have the following differences:

FunctionalityData URLCustom Scheme
Support of JavaScript-Java bridgeyesyes
Support of InjectJsCallbackyesyes
Support of InjectCssCallbackyesyes
Loading <iframe> from HTTPyesyes
Loading <iframe> from the file systemnono
Loading images from HTTPyesyes
Loading images from the file systemnono
Producing network eventsnoyes
Producing navigation eventsyesyes
Showing PDF and Print Previewyesyes
Showing PDF and Print Preview in <iframe>yesyes

Data URL

The idea of this approach is to convert the required HTML to a base64 string, generate the Data URI with the converted string, and load this URL as shown below:

Java
Kotlin
String html = "<html><body>Hello</body></html>";
String base64Html = Base64.getEncoder().encodeToString(html.getBytes(UTF_8));
String dataUrl = "data:text/html;charset=utf-8;base64," + base64Html;
browser.navigation().loadUrl(dataUrl);
val html = "<html><body>Hello</body></html>"
val base64Html = Base64.getEncoder().encodeToString(html.toByteArray(UTF_8))
val dataUrl = "data:text/html;charset=utf-8;base64,$base64Html"
browser.navigation().loadUrl(dataUrl)

You can also use the Frame.loadHtml(String html) method, it automatically generates the data URI from the given HTML:

Java
Kotlin
String html = "<html><body>Hello</body></html>";
browser.mainFrame().ifPresent(frame -> frame.loadHtml(html));
val html = "<html><body>Hello</body></html>"
browser.mainFrame().ifPresent { frame -> frame.loadHtml(html) }

The URL string must not exceed the length of 2MB due to the Chromium limit. An attempt to load URL string that exceeds this limit will be ignored by Chromium.

Custom scheme

Another approach to load HTML from string is based on InterceptUrlRequestCallback. The idea is to register the callback and intercept a specific URL request to return the required HTML as an HTTP response. For example:

Java
Kotlin
InterceptUrlRequestCallback interceptCallback = params -> {
    if (params.urlRequest().url().endsWith("?hello")) {
        byte[] bytes = "<html><body>Hello</body></html>".getBytes();
        UrlRequestJob job = params.newUrlRequestJob(
                UrlRequestJob.Options
                        .newBuilder(HttpStatus.OK)
                        .addHttpHeader(HttpHeader.of("Content-Type", "text/html"))
                        .build());
        job.write(bytes);
        job.complete();
        return InterceptUrlRequestCallback.Response.intercept(job);
    }
    return InterceptUrlRequestCallback.Response.proceed();
};

EngineOptions options = EngineOptions.newBuilder(renderingMode)
        .addScheme(HTTP, interceptCallback)
        .build();
Engine engine = Engine.newInstance(options);
Browser browser = engine.newBrowser();
browser.navigation().loadUrl("http://load.html/?hello");
val interceptCallback = InterceptUrlRequestCallback { params ->
    if (params.urlRequest().url().endsWith("?hello")) {
        val bytes = "<html><body>Hello</body></html>".toByteArray()
        val job = params.newUrlRequestJob(
            UrlRequestJob.Options
                .newBuilder(HttpStatus.OK)
                .addHttpHeader(HttpHeader.of("Content-Type", "text/html"))
                .build()
        )
        job.write(bytes)
        job.complete()
        InterceptUrlRequestCallback.Response.intercept(job)
    } else {
        InterceptUrlRequestCallback.Response.proceed()
    }
}

val options = EngineOptions.newBuilder(renderingMode)
    .addScheme(HTTP, interceptCallback)
    .build()
val engine = Engine.newInstance(options)
val browser = engine.newBrowser()
browser.navigation().loadUrl("http://load.html/?hello")

URL request that ends up with ?hello will be intercepted and the <html><body>Hello</body></html> HTML will be loaded in the browser.

Reloading

There are several options to reload the currently loaded web page:

Reload using HTTP cache:

Java
Kotlin
navigation.reload();
navigation.reload()

Reload ignoring HTTP cache:

Java
Kotlin
navigation.reloadIgnoringCache();
navigation.reloadIgnoringCache()

Reload using HTTP cache and check for repost:

Java
Kotlin
navigation.reloadAndCheckForRepost();
navigation.reloadAndCheckForRepost()

Reload ignoring HTTP cache and check for repost:

Java
Kotlin
navigation.reloadIgnoringCacheAndCheckForRepost();
navigation.reloadIgnoringCacheAndCheckForRepost()

Stopping

Use the Navigation.stop() method to cancel any pending navigation or download operation, and stop any dynamic page elements, such as background sounds and animations. For example:

Java
Kotlin
navigation.stop();
navigation.stop()

Back & forward

JxBrowser allows working with the navigation back-forward history list.

When you create a Browser instance it navigates to the about:blank web page by default, so there is always one entry in the navigation back-forward list.

To load the previous location in the back-forward list use the following approach:

Java
Kotlin
if (navigation.canGoBack()) {
    navigation.goBack();
}
if (navigation.canGoBack()) {
    navigation.goBack()
}

To load the next location in the back-forward list use:

Java
Kotlin
if (navigation.canGoForward()) {
    navigation.goForward();
}
if (navigation.canGoForward()) {
    navigation.goForward()
}

To navigate to the entry at a specific index in the back-forward list use:

Java
Kotlin
if (index >= 0 && index < navigation.entryCount()) {
    navigation.goToIndex(index);
}
if (index >= 0 && index < navigation.entryCount()) {
    navigation.goToIndex(index)
}

You can go through the back-forward list and get the details about every navigation entry:

Java
Kotlin
for (int index = 0; index < navigation.entryCount(); index++) {
    NavigationEntry navigationEntry = navigation.entryAtIndex(index);
    System.out.println("URL: " + navigationEntry.url());
    System.out.println("Title: " + navigationEntry.title());
}
for (index in 0 until navigation.entryCount()) {
    val navigationEntry = navigation.entryAtIndex(index)
    println("URL: ${navigationEntry.url()}")
    println("Title: ${navigationEntry.title()}")
}

You can modify the back-forward list by removing the entries:

Java
Kotlin
// Returns the number of entries in the back/forward list.
int entryCount = navigation.entryCount();
// Remove navigation entries at index.
for (int i = entryCount - 2; i >= 0; i--) {
    boolean success = navigation.removeEntryAtIndex(i);
    System.out.println("Was the navigation entry at the index " + i +
            " successfully removed? " + success);
}
// Returns the number of entries in the back/forward list.
val entryCount = navigation.entryCount()
// Remove navigation entries at index.
for (i in entryCount - 2 downTo 0) {
    val success = navigation.removeEntryAtIndex(i)
    println("Was the navigation entry at the index $i successfully removed? $success")
}

Filtering URLs

You can decide whether navigation request to a specific URL should be ignored or not.

The following code demonstrates how to ignore navigation requests to all URLs that start with https://www.google:

Java
Kotlin
navigation.set(StartNavigationCallback.class, params -> {
    // Ignore navigation requests to the URLs that start
    // with "https://www.google".
    if (params.url().startsWith("https://www.google")) {
        return StartNavigationCallback.Response.ignore();
    }
    return StartNavigationCallback.Response.start();
});
navigation.set(StartNavigationCallback::class.java, StartNavigationCallback { params ->
    // Ignore navigation requests to the URLs that start
    // with "https://www.google".
    if (params.url().startsWith("https://www.google")) {
        StartNavigationCallback.Response.ignore()
    } else {
        StartNavigationCallback.Response.start()
    }
})

Filtering resources

Using the BeforeUrlRequestCallback callback you can determine whether the resources such as HTML, image, JavaScript or CSS file, favicon, etc. should be loaded. By default, all resources are loaded. To modify the default behavior register your own callback implementation where you decide what resources should be canceled or loaded.

The following example demonstrates how to suppress all images:

Java
Kotlin
Network network = engine.network();
network.set(BeforeUrlRequestCallback.class, params -> {
    if (params.urlRequest().resourceType() == IMAGE) {
        return BeforeUrlRequestCallback.Response.cancel();
    }
    return BeforeUrlRequestCallback.Response.proceed();
});
val network = engine.network()
network.set(BeforeUrlRequestCallback::class.java, BeforeUrlRequestCallback { params ->
    if (params.urlRequest().resourceType() === IMAGE) {
        BeforeUrlRequestCallback.Response.cancel()
    } else {
        BeforeUrlRequestCallback.Response.proceed()
    }
})

Navigation events

Loading a web page is a complex process during which different navigation events are fired. The following diagram shows the order in which the navigation events might be fired when loading a web page: Navigation Events Flow

Load started

To get notifications when content loading has started please use the LoadStarted event. For example:

Java
Kotlin
navigation.on(LoadStarted.class, event -> {});
navigation.on(LoadStarted::class.java) { event -> }

This event corresponds to the moment when the spinner of the tab starts spinning.

Load finished

To get notifications when content loading has finished please use the LoadFinished event. For example:

Java
Kotlin
navigation.on(LoadFinished.class, event -> {});
navigation.on(LoadFinished::class.java) { event -> }

This event corresponds to the moment when the spinner of the tab stops spinning.

Navigation started

To get notifications when navigation has started please use the NavigationStarted event. For example:

Java
Kotlin
navigation.on(NavigationStarted.class, event -> {
    String url = event.url();
    // Indicates whether the navigation will be performed
    // in the scope of the same document.
    boolean isSameDocument = event.isSameDocument();
});
navigation.on(NavigationStarted::class.java) { event ->
    val url = event.url()
    // Indicates whether the navigation will be performed
    // in the scope of the same document.
    val isSameDocument = event.isSameDocument()
}

Navigation stopped

To get notifications when navigation has stopped please use the NavigationStopped event. For example:

Java
Kotlin
navigation.on(NavigationStopped.class, event -> {});
navigation.on(NavigationStopped::class.java) { event -> }

This event is fired when navigation is stopped via the Navigation.stop() method.

Navigation redirected

To get notifications when navigation has been redirected to a new URL please use the NavigationRedirected event. For example:

Java
Kotlin
navigation.on(NavigationRedirected.class, event -> {
    // The navigation redirect URL.
    String url = event.destinationUrl();
});
navigation.on(NavigationRedirected::class.java) { event ->
    // The navigation redirect URL.
    val url = event.destinationUrl()
}

Navigation finished

To get notifications when navigation has finished please use the NavigationFinished event. For example:

Java
Kotlin
navigation.on(NavigationFinished.class, event -> {
    String url = event.url();
    Frame frame = event.frame();
    boolean hasCommitted = event.hasCommitted();
    boolean isSameDocument = event.isSameDocument();
    boolean isErrorPage = event.isErrorPage();
    if (isErrorPage) {
        NetError error = event.error();
    }
});
navigation.on(NavigationFinished::class.java) { event ->
    val url = event.url()
    val frame = event.frame()
    val hasCommitted = event.hasCommitted()
    val isSameDocument = event.isSameDocument()
    val isErrorPage = event.isErrorPage()
    if (isErrorPage) {
        val error = event.error()
    }
}

This event is fired when navigation is committed, aborted, or replaced by a new one. To know if the navigation has committed, use NavigationFinished.hasCommitted(); use NavigationFinished.isErrorPage() to know if the navigation resulted in an error page.

If the event is called because the navigation committed, the document load will still be ongoing.

The event is fired by same-document (in the scope of the same document) navigations, such as fragment navigations or window.history.pushState()/window.history.replaceState(), which will not result in a document change. Please use NavigationFinished.isSameDocument() to check if it is a same-document navigation.

Frame load finished

To get notifications when content loading in the Frame has finished please use the FrameLoadFinished event. For example:

Java
Kotlin
navigation.on(FrameLoadFinished.class, event -> {
    String url = event.url();
    Frame frame = event.frame();
});
navigation.on(FrameLoadFinished::class.java) { event ->
    val url = event.url()
    val frame = event.frame()
}

This event corresponds to the moment when the content in the Frame has been loaded completely.

Frame load failed

To get notifications when content loading in the Frame has failed for some reason, use the FrameLoadFailed event. For example:

Java
Kotlin
navigation.on(FrameLoadFailed.class, event -> {
    String url = event.url();
    NetError error = event.error();
});
navigation.on(FrameLoadFailed::class.java) { event ->
    val url = event.url()
    val error = event.error()
}

Frame document load finished

To get notifications when the document loading in the Frame has finished please use the FrameDocumentLoadFinished event. For example:

Java
Kotlin
navigation.on(FrameDocumentLoadFinished.class, event -> {
    Frame frame = event.frame();
});
navigation.on(FrameDocumentLoadFinished::class.java) { event ->
    val frame = event.frame()
}

At this point, deferred scripts were executed, and the content scripts marked “document_end” get injected into the frame.