Blog

Make the loading indicator in Vaadin great again

By  
Sebastian Kuehnau
Sebastian Kuehnau
·
On Jul 24, 2025 6:10:58 PM
·

Every interaction in a Vaadin UI sends a request to the server. If that response takes longer than ~300 ms, Vaadin shows a loading bar across the top of the page to prevent user confusion. It appears the moment the request leaves the browser and disappears as soon as the response returns.

Default behaviour

While the loading-indicator is running, the browser tab cannot send additional requests (caused by user interactions). With default configuration the loading indicator is a small bar on top of the body of the application in the browser and only visible until the server responds back to the browser. 

Technically the loading indicator is a fixed <div> that Vaadin toggles through three stages (450 ms, 1500 ms, 5000 ms) to visualise latency.

HTML snippet showing Vaadin's layout structure, with a highlighted <div id='outlet'> for rendering views and a <div class='v-loading-indicator'> used for displaying the loading indicator.

It is possible to change the default configuration of the component and set different delays for the stages via a Java API as well as modify the color and the size of the progress bar. For more information, I recommend reading the documentation and get a full overview of how to change the configuration.

Animated demo of a Vaadin view where clicking the 'Do Heavy Work' button triggers a custom loading indicator.

Changing the default

In this article I’m going to show various options how you could change the style of the loading-indicator to make it more visible or change the color. I also go into what best practices there are to visualize running processes to the end user.

By default the loading-indicator is rather subtle and enables further interaction with the application, although this cannot be answered ad-hoc by the server (because the previous request of this UI session is still running). Thus, it can happen that if a user presses a button several times and it responds with a corresponding latency, the processes are executed sequentially on the server and the user has to wait a correspondingly long time. This could lead to confusion and frustration because the application does not respond according to the latest interaction.

In order to prevent multiple requests to the server, it is possible to deactivate all components with an overlay for the duration of the request and enable them again when the server is ready to receive new requests. Visually, you could darken the application, blur the background with an overlay element and add a suitable loading icon (for example a sand clock).

The appearance of the loading-indicator can be easily controlled via CSS. The underlying DIV element has the class name “v-loading-indicator” and adjustments can be made in the styles.css file.

For example, if you want to change the color and the height of the element you could add the following lines to your styles.css:

```css
.v-loading-indicator {
  height: 20px!important;
  background-color: orange!important;
}
```

If you want to replace the standard loading-indicator with your own solution, you must switch off the default theme for it beforehand. How to do this is explained in the documentation.

Advanced configuration

The documentation also describes how to darken the entire application interface during the loading process with the help of a modal curtain. To do this, you need to define an overlay over the entire screen first and set the Z-index accordingly. To make the transition more dynamic and less surprising, you can define your own animations with the help of a @keyframe definition and refer to them in the animation property in the corresponding CSS Definition.

```css
.v-loading-indicator {
  position: fixed; /* Occupy whole screen even if scrolled */
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  /* stop all mouse events */
  pointer-events: none;
  /* Animated with delay to prevent flashing, 
fadein-effect is defined below */
  animation: fadein 0.3s ease-in-out 0.1s normal 1 both;
  z-index: 2147483647;
}

@keyframes fadein {
  0% {
      background: rgba(0,0,0,0);
  }
  100% {
      background: rgba(0,0,0,.5);          /* Darkens the UI */
  }
}
```

To blur the background, extend the CSS definition with the property backdrop-filter: blur(5px); and the entire components of the application will be blurry. For compatibility in Safari, the property: -webkit-backdrop-filter: blur(0px);

It is also possible to add a loading animation (rotating flower, hourglass or a rotating wheel) with a gif file and display it centered on the screen. To keep the integration consistent, the gif file should be placed in the themes directory (src/main/frontend/themes/<theme-name>/) next to the styles.css file or into a subfolder. The location can be different in larger projects depending on your architecture guidelines. To define the link to the gif file and configure the exposure use the following line to the animation definition:

```css
background-image: url('loading.gif');
background-size: 50px 50px;
background-position: center;
background-repeat: no-repeat;
```

The final overall definition looks the following:

```css
@keyframes fadein {
  0% {
      background: rgba(0,0,0,0);
      backdrop-filter: blur(0px);          /* Blur-Effect */
      -webkit-backdrop-filter: blur(0px);  /* Safari-Support */
   }

  100% {
      background: rgba(0,0,0,0.5);         /* Darkens the UI */
      backdrop-filter: blur(5px);          /* Blur-Effect */
      -webkit-backdrop-filter: blur(5px);  /* Safari-Support */
      background-image: url('loading.gif');
      background-size: 50px 50px;
      background-position: center;
      background-repeat: no-repeat;
  }
}
```

And it finally looks like this: 

Image of the spinning loading indicator.

Asynchronous loading as an alternative

Alternatively, you also have the option of bypassing server latencies with the Vaadin push mechanism and transferring the result to the client asynchronously. This method is of course preferable if the long server request is known in advance.

Conclusion

In the article I have shown how you can customize the Vaadin's loading indicator to your needs and create a better user experience. The example project is available on my GitHub, where you can explore both the default configuration and a more advanced implementation.

Want to take it even further? Consider using animations to enhance the user experience. You can find a wide selection of free, high-quality animations at LottieFiles, and check out our earlier guide on integrating Lottie animations into Java apps with Vaadin.

Was this helpful? Do you have other solutions? Join the discussion at vaadin.com/forum.