Vaadin Fusion Quick Start
Vaadin Fusion enables you to integrate a Spring Boot Java backend with a reactive TypeScript frontend. It includes all the UI components and tools you need so you can focus on building your app instead of configuring stuff.
In this guide, you learn how to build a small but fully functional shopping-list application using Vaadin Fusion.
What You Need
About 10 minutes
JDK 8 or higher (For example, Eclipse Temurin JDK).
Step 1: Download a Vaadin Fusion Project
Unpack the downloaded zip into a folder on your computer, and import the project in the IDE of your choice.
The pre-configured starter project includes an empty Grocery
view written in Typescript that you will modify as described further below.
Step 2: Define the Data Model
For the data model, define a plain old Java object (POJO) by creating a new GroceryItem.java
file in src/main/java/com/example/application/
with the following content:
package com.example.application;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
public class GroceryItem {
@NotBlank 1
private String name;
@NotNull
@Min(value = 1) 2
private Integer quantity;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
}
Add a
@NotBlank
annotation to ensure that the item’sname
is non-null and that it contains at least one non-whitespace character.Add
@NotNull
and@Min
annotations to ensure that the item’squantity
is a non-null integer that is greater than 0.
Step 3: Create a Typed Server Endpoint
Vaadin Fusion enables your frontend to have secure, type-safe access to the server through REST-like endpoints.
Create a new GroceryEndpoint.java
file in src/main/java/com/example/application/
with the following content:
package com.example.application;
import com.vaadin.flow.server.auth.AnonymousAllowed;
import com.vaadin.fusion.Endpoint;
import com.vaadin.fusion.Nonnull;
import java.util.ArrayList;
import java.util.List;
@Endpoint 1
@AnonymousAllowed 2
public class GroceryEndpoint {
static final List<GroceryItem> groceryList = new ArrayList<>();
public @Nonnull List<@Nonnull GroceryItem> getGroceries() { 3
return groceryList;
}
public GroceryItem save(GroceryItem item) {
groceryList.add(item);
return item;
}
}
Annotating the class with
@Endpoint
exposes it as a service for client-side views. All public methods of an endpoint are callable from TypeScript.By default, endpoint access requires an authenticated user.
@AnonymousAllowed
enables access for anyone. See Configuring Security for more information on endpoint security.Using the
@Nonnull
annotation ensures that the TypeScript Generator does not interpret these values as possiblyundefined
.
Step 4: Create a Reactive UI in TypeScript
Vaadin Fusion uses the Lit library to create client-side views. Lit is a lightweight and highly performant library for building reactive UI.
Open frontend/views/grocery/grocery-view.ts
and replace its contents with the following:
import '@vaadin/vaadin-button';
import '@vaadin/vaadin-text-field';
import '@vaadin/vaadin-text-field/vaadin-number-field';
import '@vaadin/vaadin-grid/vaadin-grid';
import { html } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import '@vaadin/vaadin-lumo-styles/sizing';
import '@vaadin/vaadin-lumo-styles/spacing';
import { View } from '../../views/view';
import { Binder, field } from '@vaadin/form';
import { getGroceries, save } from '../../generated/GroceryEndpoint';
import GroceryItem from 'Frontend/generated/com/example/application/GroceryItem';
import GroceryItemModel from 'Frontend/generated/com/example/application/GroceryItemModel';
@customElement('grocery-view') 1
export class GroceryView extends View { 2
@state()
private groceries: GroceryItem[] = []; 3
private binder = new Binder(this, GroceryItemModel); 4
render() {
return html`
<div style="padding: 25px">
<div>
<vaadin-text-field ${field(this.binder.model.name)} label="Item">
</vaadin-text-field> 5
<vaadin-number-field
${field(this.binder.model.quantity)}
has-controls
label="Quantity"
></vaadin-number-field> 6
<vaadin-button theme="primary" @click=${this.addItem} ?disabled=${this.binder.invalid}>
Add</vaadin-button> 7
</div>
<h3>Grocery List</h3>
<vaadin-grid .items="${this.groceries}" theme="row-stripes" style="max-width: 400px"> 8
<vaadin-grid-column path="name"></vaadin-grid-column>
<vaadin-grid-column path="quantity"></vaadin-grid-column>
</vaadin-grid>
</div>
`;
}
async addItem() {
const groceryItem = await this.binder.submitTo(save); 9
if (groceryItem) { 10
this.groceries = [...this.groceries, groceryItem];
this.binder.clear();
}
}
async firstUpdated() { 11
const groceries = await getGroceries();
this.groceries = groceries;
}
}
Register the new component with the browser. This makes it available as
<grocery-view>
. The routing inindex.ts
is already set up to show it when you navigate to the application.Define the component class that extends from Vaadin
View
class, which itself extends fromLitElement
.The list of
groceries
is private and decorated with@state()
so Lit observes it for changes.A Vaadin
Binder
is used to handle the form state for creating new GroceryItems.GroceryItemModel
is automatically generated by Vaadin. It describes the data types and validations thatBinder
needs. Read more about forms in Creating Client-Side Forms.The Text Field component is bound to the
name
property of aGroceryItem
using element expression:${field(this.binder.model.name)}
.Analogous to the Text Field, the Number Field is bound to the
quantity
property of aGroceryItem
using${field(this.binder.model.quantity)}
.The click event of the Add button is bound to the
addItem()
method. The button is disabled if the form is invalid.Use Vaadin Grid to display the current content of the grocery list.
Use binder to submit the form to
GroceryEndpoint
. The binder validates the input before posting it and the server re-validates it.If the
GroceryItem
was saved successfully, update thegroceries
array and clear the form.Retrieve the list of groceries from the server upon the view’s first rendering.
Step 5: Run the Application
To run the project in your IDE, launch Application.java
, which is located under src/main/java/com/example/application/
.
Alternatively, you can run the project from the command line by typing mvnw
(on Windows), or ./mvnw
(on macOS or Linux).
Then, in your browser, open localhost:8080/grocery
.
Go further
Congratulations on finishing the tutorial! Now you have a taste of how Vaadin Fusion empowers you to quickly build web apps that integrate a Java backend with a reactive TypeScript frontend.
Continue exploring Vaadin Fusion in the following resources:
If you get stuck or need help, please reach out to the Vaadin Community in Discord.
The full source code of this project is available on GitHub.