Blog

Five methods to create grid layouts with Vaadin Flow

By  
Matti Tahvonen
Matti Tahvonen
·
On Jul 2, 2024 11:49:41 AM
·

Vaadin ships with a powerful Grid component to display tabular data but is missing a built-in component for grid layouts. In theory, you could use the API in the data grid to lay out components, but this quickly leads to suboptimal performance, and the API is not designed for generic layouts. If you are not listing data items, there are much better options available.

Until version 8, Vaadin shipped with a rather powerful GridLayout component in its core component set. Since then, you have needed to choose from various add-ons or build it yourself. Let's quickly cover some top options.

1. Simulate Grid with ordered layouts

In trivial cases, if your content in columns is equally sized, you might not need a grid at all. With the rather powerful features of HorizontalLayout and VerticalLayout, one can essentially build a grid from them.

In the following example, we are recreating a subset of the Bootstrap-like grid system plain HorizontalLayout and VerticalLayout.

/**
 * A subset of a Bootstrap-like grid system implemented with basic layouts.
 */
public class GridWithBasicLayouts extends VerticalLayout {

    public static class Row extends Composite<HorizontalLayout> {
        public Row() {
            getContent().setSpacing(false);
            getContent().setSizeFull();
        }

        /**
         * Adds a component with a given colspan.
         *
         * @param component the component
         * @param colspan   the colspan, like a 12-column Bootstrap grid (12 == full width)
         */
        public void addCell(Component component, int colspan) {
            getContent().add(component);
            component.getStyle().setWidth(100 * (colspan / 12.0) + "%");
        }
    }

    public GridWithBasicLayouts() {
        setSpacing(false);
        add(
            new Row() ,
            new Row() ,
            new Row() ,
            new Row() 
        );
    }

    private Random random = new Random(0);

    private Div createContent(String textContent) {
        Div div = new Div(textContent);

        // Generate a pseudorandom color to visualize the output
        int nextInt = random.nextInt(0xffffff + 1);
        String colorCode = String.format("#%06x", nextInt);
        div.getStyle().setBackground(colorCode);
        div.setMinHeight("100px");

        return div;
    }
}

2. V8 GridLayout mimicking add-ons

In case your use case for grid layout is a migration from an older version of Vaadin, the natural choice is an add-on that mimics the API of the old GridLayout. Vaadin Prime customers can nowadays drop in a component that provides many of the same features as the Vaadin 8 GridLayout.

A free solution is available for OSS users. It has slightly smaller API coverage (for example, missing “expand ratios”), but this component has proven to work well on several migration projects.

3. Solutions based on HTML Table element

Like the Grid component in Vaadin, the Table element in HTML is primarily designed to display tabular data. Infamously, the table element (and tr/td etc.) has for decades been “misused” for layouting. In the early days of web apps, it was the only sensible way to build complex layouts. Right or wrong, it is a proven solution and can be a well-argued approach for layouting, especially if migrating from a solution that already uses an HTML table-based layout.

Thanks to the powerful Element API in Flow, designed to build component integrations to the browser DOM, many Vaadin developers have built custom components around table, tr and td elements. This is good as you can abstract away the somewhat misused HTML elements. 

Alternatively, you can compose your layout using the popular component API from the HTML Table addon. It provides a well-typed API that guides you in the HTML table usage, similar to what we provide with the core for many other raw HTML elements. It is super handy if you don’t remember all the details of HTML table specifications by heart. If you are afraid of leaking the API in your component, use it through the Composite component. Below, you’ll see an example code using the HTML Table add-on. For Vaadin 24.5, there is a similar core component API in the queue.

var table = new Table();

var row = table.addRow();
row.addHeaderCell().setText("Name");
row.addHeaderCell().setText("Age");

var textField = new TextField();
var numberField = new NumberField();

row = table.addRow();
row.addDataCell().add(textField);
row.addDataCell().add(numberField);

add(table);

The above code would produce the following HTML to be rendered in the browser:

<table>
  <tr>
    <th>Name</th>
    <th>Age</th>
  </tr>

  <tr>
    <td>
      <vaadin-text-field></vaadin-text-field>
    </td>

    <td>
      <vaadin-number-field></vaadin-number-field>
    </td>
  </tr>
</table>

4. Bootstrap Grid system-like solutions

The Bootstrap front-end framework popularized a grid-based layout system with pre-built responsive steps. Since then, derived solutions have been developed in several front-end tools, such as the Tailwind CSS framework.

These grid layout approaches can naturally be used in Vaadin applications as well via the Element API. If you’d rather stay on a higher abstraction level (like you most often should), you could drop in one of the existing Bootstrap add-ons.

5. Building on top of the CSS Grid

The CSS Grid is the most advanced native layout mechanism supported by modern browsers. Similar to the table element, there is no built-in component available for it in the core API, but CSS Grid is perfectly usable through the Element API (and its Style object) or via community-provided add-ons. There is an older add-on built with templates and shadow DOM, and I recently built one using plain CSS and div elements.

The complete CSS Grid specification is huge; some might even say it is bloated. After my recent effort in modeling a Java API for the CssGrid I’m not convinced that it should be used directly in applications. But it is a great basis for building various custom layouts. It can mimic, e.g., Bootstrap-like systems and many good old Swing layouts. So, instead of using the complex do-what-ever-you-want type of CssGrid class directly in your application, I suggest utilizing it to create your domain-specific layouts with a clean Java API.

As an example, I drafted a version of the good old “border layout” from Swing, implemented using CssGrid. It uses the Composite class to hide irrelevant API and only expose a clean and easy-to-use Java API for end users. The implementation of the example class is shown below (JavaDocs and imports excluded).

public class BorderLayoutWithCssGrid extends Composite<CssGrid>
   implements HasSize {

   public BorderLayoutWithCssGrid() {
       // Configure CssGrid so that middle col takes all left from others
       getContent().setTemplateColumns("0fr 1fr 0fr");
       // middle row takes all left from others
       getContent().setTemplateRows("0fr 1fr 0fr");
   }

   public void setChildAt(Region region, Component component) {
       getContent().add(component)
               .withColumns(region.colStart,region.colEnd)
               .withRow(region.row);
   }

   public void setGap(String gapCssLenth) {
       // exposing the setGap method from CssGrid
       getContent().setGap(gapCssLenth);
   }

   public enum Region {
       NORTH(1,4,1),
       SOUTH(1,4,3),
       EAST(1,1,2),
       WEST(3,4,2),
       CENTER(2,2,2);

       int colStart;
       int colEnd;
       int row;

       Region(int colStart, int colEnd, int row) {
           this.colStart = colStart;
           this.colEnd = colEnd;
           this.row = row;
       }
   }
}

The example class, with some colorful content that has a minimum size of 100px, renders like this:

An example of how a grid layout is rendered with color-coded regions.

Wrapping up

Vaadin offers multiple methods for creating grid layouts, from using HorizontalLayout and VerticalLayout for simple grids to leveraging HTML table elements and the advanced CSS Grid. While the core API lacks a built-in grid layout component, add-ons and the Element API in Vaadin Flow provide powerful alternatives. These options ensure flexibility and optimal performance in your web applications. Whether migrating from an older Vaadin version or building new projects, you can find the right solution for your needs.

New to Vaadin? Start a new project today or explore our Getting Started tutorial to learn the basics.

Matti Tahvonen
Matti Tahvonen
Matti Tahvonen has a long history in Vaadin R&D: developing the core framework from the dark ages of pure JS client side to the GWT era and creating number of official and unofficial Vaadin add-ons. His current responsibility is to keep you up to date with latest and greatest Vaadin related technologies. You can follow him on Twitter – @MattiTahvonen
Other posts by Matti Tahvonen