Force the browser to download the content

The best way to achieve that is to use the Vaadin Anchor component, setting href to appropriate StreamResource. That way, the browser will correctly open the download dialog by default, working as expected. Tags: FileDownloader.

If you want to have a download icon, you can simply add the Icon component into Anchor like follows:

Anchor a = new Anchor(...);
a.add(new Icon(VaadinIcon.ABACUS));

This may not work with the Vaadin Button though, since the button may steal clicks.

Programmatic Downloads

You can try to call window.open as follows, on button click, to open the download in a new popup:

button.getElement().executeJs("window.open($0)", registration.getResourceUri().toString()));

Note that Firefox will block the popup by default - you will need to tell the user to disable popup blocking for your site.

On top of that, unfortunately it’s not possible to tell window.open to force-download the target content:

  • using window.location.href = [url] instead of window.open might seem to be working (it works for PDF and CSV files), but HTML and JSON files are still displayed inline in the browser, rather than being downloaded.
  • The same by setting target to _parent.

The only way is to set the Content-Disposition HTTP header header to attachment.

This feature has been added to Vaadin 22 and Vaadin 14.8+, see flow #5471 for more details.

Example code:

@Route("")
public class MainView extends VerticalLayout {

    public static class DownloadOnClickExtension implements Serializable {

        private StreamRegistration registration;

        public DownloadOnClickExtension(Button button) {
            button.addAttachListener(e -> registerResource());
            if (button.isAttached()) { registerResource(); }
            button.addDetachListener(e -> {
                registration.unregister();
                registration = null;
            });
            button.addClickListener(e ->
                    button.getElement().executeJs("window.location.href = $0", registration.getResourceUri().toString()));
        }

        private void registerResource() {
            final StreamResource resource = new StreamResource("hello.txt",
                    (InputStreamFactory) () -> new ByteArrayInputStream("Hello, world".getBytes(StandardCharsets.UTF_8)));
            resource.setHeader("Content-Disposition", "attachment");
            registration = VaadinSession.getCurrent().getResourceRegistry().registerResource(resource);
        }
    }

    public MainView() {
        final Button button = new Button("Download file");
        new DownloadOnClickExtension(button);
        add(button);
    }
}
Written on December 15, 2021