GitHub

User guideResources

Put JavaScript at the end of the body

Render all script header items in a container just before the closing body tag with JavaScriptFilteredIntoFooterHeaderResponse and HeaderResponseContainer.

How-toWicket 10 and later

Move scripts to the end of the body when you want the browser to render the page before it downloads and runs the JavaScript. Components keep calling renderHead; a header response decorator sorts their items into the head and into a container at the bottom of the page.

Register a JavaScriptFilteredIntoFooterHeaderResponse in init(). The second argument names the bucket for the scripts:

WicketApplication.java

@Override
protected void init() {
    super.init();
    getHeaderResponseDecorators().add(
        response -> new JavaScriptFilteredIntoFooterHeaderResponse(response, "footer-scripts"));
}

From now on, every JavaScriptHeaderItem, OnDomReadyHeaderItem, OnLoadHeaderItem and OnEventHeaderItem goes into the footer-scripts bucket. Stylesheets, meta tags and the markup of the page’s own <head> stay in the head.

add places the decorator inside the resource aggregation, so dependencies, bundles and ordering still apply before the items are sorted into buckets, and Wicket still adds the Content Security Policy nonce to every script.

Render the bucket in the page

Add a HeaderResponseContainer with the bucket name to every page, as the last element of the body. A base page does it once for all pages:

BasePage.java

public abstract class BasePage extends WebPage {

    public BasePage() {
        add(new HeaderResponseContainer("footerScripts", "footer-scripts"));
    }
}

BasePage.html

<!DOCTYPE html>
<html xmlns:wicket="http://wicket.apache.org">
<head>
    <meta charset="utf-8"/>
    <title>Example</title>
</head>
<body>
    <wicket:child/>
    <wicket:container wicket:id="footerScripts"/>
</body>
</html>

The first argument is the component id, the second the bucket name. The container renders only the script tags, not its own tag. A page that renders script items without the container loses those scripts, so make sure every page extends the base page.

During an Ajax request Wicket sends header items with the Ajax response as usual, so components updated with Ajax keep working.

Keep one script in the head

Some scripts must run before the body renders, for example one that sets a theme class on the document to prevent a flash of the wrong colours. Wrap its item in a FilteredHeaderItem with the name of the head bucket:

@Override
public void renderHead(IHeaderResponse response) {
    super.renderHead(response);
    response.render(new FilteredHeaderItem(
        JavaScriptHeaderItem.forReference(ThemeJs.get()),
        FilteringHeaderResponse.DEFAULT_HEADER_FILTER_NAME));
}

A FilteredHeaderItem goes into the bucket it names, whatever the filters say, and its dependencies follow it. The same works the other way: wrap an item with your own bucket name and render that bucket with another HeaderResponseContainer anywhere in the page.

Defer scripts instead

If you only want scripts not to block rendering, adding defer to the script tags in the head has the same effect without a container: JavaScriptHeaderItem.forReference(…).setDefer(true). To defer every script of the application, Wicket has JavaScriptDeferHeaderResponse, which it marks as experimental. The decorators are listed in Header items.