Docs

Documentation versions (currently viewingVaadin 24)

Data Grids

Quickly create data grids using the Auto Grid feature.

Auto Grid makes it easy to show data from a database in a grid. It works by connecting a JPA repository to a grid component — and with minimal effort. The grid shows columns for all properties of the entity, and loads data in a lazy-loaded manner. It can also provide sorting and filtering.

This guide shows how to set up a JPA entity and repository in the backend, how to expose the repository with a service, and how to connect that service to an Auto Grid in the frontend.

If you don’t have a Hilla project yet, you can quickly create one by running the following command from the CLI:

npx @hilla/cli init my-hilla-app

Setting up the Backend

To use Auto Grid, you need to have JPA and a database in your project. If you haven’t done this already, open the following section on how to configure JPA and an in-memory H2 database. Otherwise, you can skip it.

Database Setup

First, add the following dependencies to the pom.xml file:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>

Next, add the following properties to the src/main/resources/application.properties file:

spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update

First, create a JPA entity class in the backend. For this guide, you’ll use a simple entity that represents a product. Create a Product.java file next to Application.java with the following content:

package com.example.application;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

import java.time.LocalDate;

@Entity
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String category;
    private double price;
    private LocalDate dateAdded;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getCategory() {
        return category;
    }

    public void setCategory(String category) {
        this.category = category;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public LocalDate getDateAdded() {
        return dateAdded;
    }

    public void setDateAdded(LocalDate dateAdded) {
        this.dateAdded = dateAdded;
    }
}

Next, create a Spring JPA repository for the entity. Create a ProductRepository.java file next to Product.java with the following content:

package com.example.application;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;

public interface ProductRepository extends JpaRepository<Product, Long>, JpaSpecificationExecutor<Product> {
}

Finally, create a service to expose the repository to the frontend. Create a ProductService.java file next to ProductRepository.java with the following contents:

package com.example.application;

import com.vaadin.flow.server.auth.AnonymousAllowed;
import com.vaadin.hilla.BrowserCallable;
import com.vaadin.hilla.crud.ListRepositoryService;

@BrowserCallable
@AnonymousAllowed
public class ProductService extends ListRepositoryService<Product, Long, ProductRepository> {
}

This service is annotated with @BrowserCallable to allow it to be called from the frontend. It extends ListRepositoryService, which provides a default implementation for fetching paginated, sorted, and filtered data. By default, all services exposed to the frontend are secured and require authentication. To keep things simple, the service has the @AnonymousAllowed annotation to allow unauthenticated access to the service.

In order to have some example product data, download this SQL script and put it in the src/main/resources folder:

Download product data

Creating the View

Now that the backend is set up, you can implement the frontend part. Start by running the application, using the default Maven goal:

mvn

This takes a while to install all necessary dependencies, but once it is done, you should see the application in your browser.

Next, create a view that renders the product data. Create a products.tsx file in the frontend/views folder with the following content:

import React from 'react';
import { AutoGrid } from '@vaadin/hilla-react-crud';
import { ProductService } from 'Frontend/generated/endpoints';
import ProductModel from 'Frontend/generated/com/example/application/ProductModel';

export function ProductsView() {
  return (
    <div className='p-l'>
      <AutoGrid service={ProductService} model={ProductModel} />
    </div>
  );
}

This view renders an Auto Grid component, configured to load data from the ProductService and using the ProductModel to define the columns. The ProductModel is generated from the Product entity in the backend that you created earlier.

Save the file and open the URL, http://localhost:8080/products in your browser. You should see a grid like the following, showing product data from the database:

Open in a
new tab
import { AutoGrid } from '@vaadin/hilla-react-crud';
import ProductModel from 'Frontend/generated/com/vaadin/demo/fusion/crud/ProductModel';
import { ProductService } from 'Frontend/generated/endpoints';

function Example() {
  return <AutoGrid service={ProductService} model={ProductModel} />;
}

Further Information

For more information about the Auto Grid feature, see the Auto Grid documentation.