Documentation versions (currently viewingVaadin 24)

Add a View

How to add a view to a Vaadin starter application.

When you configured your project in Vaadin Start (, you added views through the user interface. On this page, you’ll see how to add views to the project, directly. As of Vaadin 24.4, you can write your views using either Flow and Java, or React and TypeScript — in the same application.

Add a Flow View

Views in a Flow application are Java classes annotated with @Route that also extend com.vaadin.flow.component.Component — or any of its subclasses. You would typically extend a layout such as HorizontalLayout, VerticalLayout, or your own base class.

You can create view classes anywhere inside your project. Projects generated by Vaadin Start store their views inside a sub-package called views. For instance, if the application package is com.example.application, the views are stored in com.example.application.views.

For this next step, add a new view to your application. The view should be a small, but fully functional ToDo list. Start by creating a new sub-package called, todo inside the views package. Next, create a new Java class inside this package called TodoView. Finally, replace the code in the class with the following:

package com.example.application.views.todo;

import com.vaadin.flow.component.Key;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.Route;

@Route("todo") // (1)
public class TodoView extends VerticalLayout { // (2)

  public TodoView() {
    var todosList = new VerticalLayout(); // (3)
    var taskField = new TextField(); // (4)
    var addButton = new Button("Add"); // (5)
    addButton.addClickListener(click -> { // (6)
      Checkbox checkbox = new Checkbox(taskField.getValue());
    addButton.addClickShortcut(Key.ENTER); // (7)
    add( // (8)
      new H1("Vaadin Todo"),
      new HorizontalLayout(
  1. The @Route annotation makes the view accessible to the end user, in this case using the todo route.

  2. As the TodoView class extends VerticalLayout, components added to it are ordered vertically.

  3. The todosList is a vertical layout that displays a list of the tasks along with checkboxes.

  4. The taskField is a text input field to enter the description of new tasks.

  5. The addButton is a button for adding a new task.

  6. In the listener for the button click, first create a new checkbox with the value from the taskField as its label. Then add the checkbox to the todosList.

  7. Add a shortcut for the addButton component when the Enter key is pressed.

  8. Call add() on the VerticalLayout to display the components, vertically. Notice that taskField and addButton are in a HorizontalLayout. That puts them next to each other.

If your application is running in development mode, you should now be able to go to http://localhost:8080/todo to try your new view.

Add a React View

Projects generated by Vaadin Start use the file-system router, by default. The views are React components in the src/main/frontend/views directory and their routes are deduced based on the directory structure and file naming. The main view — corresponding to the empty route — is declared in the file src/main/frontend/views/@index.tsx.

Add a new view to your application. The view should be a small, but fully functional ToDo list. To do this, create a new file inside the src/main/frontend/views directory called todo.tsx. Then copy the following code into it:

import { useSignal } from "@vaadin/hilla-react-signals";
import { Checkbox, HorizontalLayout, VerticalLayout } from "@vaadin/react-components";
import { TextField } from "@vaadin/react-components/TextField.js";
import { Button } from "@vaadin/react-components/Button.js";
import { ViewConfig } from "@vaadin/hilla-file-router/types.js";

export const config: ViewConfig = { // (1)
    menu: { order: 1, icon: 'line-awesome/svg/tasks-solid.svg' },
    title: "Vaadin Todo"

export default function TodoView() {
    const todos = useSignal<string[]>([]) // (2)
    const task = useSignal<string>("") // (3)

    function addTask() { // (4)
        todos.value = [...todos.value, task.value]
        task.value = ""

    return <VerticalLayout theme="spacing padding">
            {,index) => <Checkbox key={index} label={todo}/>)} {/* <5> */}
        <HorizontalLayout theme="spacing">
            <TextField value={task.value} onChange={e => task.value =}/> {/* <6> */}
            <Button onClick={addTask}>Add</Button> {/* <7> */}
  1. Additional view configuration parameters, like the view title and icon, are declared like this.

  2. A signal is used to store the items of the ToDo list.

  3. Another signal is used to store the description of the next task to add to the ToDo list.

  4. When the user clicks the Add button, the task is added to the ToDo list.

  5. Each item in the ToDo list is rendered as a checkbox.

  6. The text field is used to enter the description of new tasks. It’s bound to the task signal.

  7. The button is used to add new tasks to the ToDo list. When clicked, the addTask() function is called.

If your application is running in development mode, you should now be able to go to http://localhost:8080/todo to try your new view.