The road to responsive tables in Mendix
--
In this blog post, I look at different ways to build nice-looking responsive tables in Mendix using only standard Mendix widgets and CSS. For starters, let's look at data grids, which are the standard way to create a table in Mendix.
Data grid
This widget works great for static data. It is very quick to set up, and just by connecting the widget to an entity, Mendix will automatically generate all the columns and search fields. This is a great widget and I use it frequently, especially for administration CRUD pages, where look&feel are not the primary concerns. That being said, it is not very customizable. For example, there is no way to have an inline button, at least not without some hacking. To address this issue one could try using a list view in a combination with a table.
List view + Table
Unlike data grids, list views work with most widgets, e.g. buttons, date selectors, etc. With a bit of CSS, the header and the list views can be made to look like a table. See it in action here.
One really annoying issue with this approach is that the size of the columns is specified twice: once for the header and once for the body. This combined with the semi-automatic calculation of column widths that Mendix does makes it painful to change anything related to the columns.
In terms of layout, the table supports rescaling using either percentages or fixed size columns with a single auto
column that fills up all the remaining available space. That is all good, but what about the following example: a table with two fixed-size columns and three responsive columns, one of which should be twice as large as the other two. This is not possible with the table widget but is possible with flex.
List view + Flex
Flex is a CSS concept that aims to provide an easy and efficient way to distribute space among items in a container, even when their size is unknown. With flex, it is easy to define different column sizes such as fixed or responsive with min and max size. Furthermore, it is also possible to define relative sizes for a column e.g. make a column twice as big as another column while keeping both responsive. Below is an implementation of a Mendix table using flex.
Notice how the same classes are used for both the header and body columns. This makes it possible to easily define the size of each column without duplication, unlike in the previous approach. Here is the stylesheet:
.flex-table {
& .flex-table-row, .flex-table-header-row {
display: flex; // nested HTML elements should be layed out using flex
width: 100%; // the row should fill out all availble space of the parent element> div {
padding: 5px; // some padding for all columns
}
& > .column-id { // responsive column with min and max width
min-width: 150px;
max-width: 300px;
flex-grow: 100;
}
& > .column-toggle { // fixed size column
width: 100px;
}
& > .column-timestamp { // fixed size column
width: 150px;
}
& > .column-name { // responsive column with min width
min-width: 100px;
flex-grow: 100;
}
& > .column-description { // responsive and twice as large as column-name
min-width: 200px;
flex-grow: 200;
}
}
& .flex-table-header-row > div {
position: sticky; top: 0; z-index: 999; // keep header visible while scrolling
font-weight: bold; background-color: lightgrey; // styling for header cells
}
}
The result is a responsive table where column sizes are highly customizable.
Amazing as flex is, it has a major issue. Namely, flex containers only align items in one direction, in our case horizontally and are completely oblivious to what is happening in the other direction. This causes issues when for example a cell in a row has large content and thus needs more space. The flex container for that row will happily deal with the situation and make room for the large content. However, none of the other rows will expand, making it look like something went horribly wrong:
Because flex layout in a row is ignorant of other rows it can easily result in misaligned columns.
To get the desired behavior we need to use another CSS concept called grid.
List view + Grid
Grid is an extension of flex to two dimensions.
Changing from using flex to grid is fairly straightforward. The page structure in Mendix is the same as for flex. In terms of CSS, the way in which column sizes are defined is a bit different. Also, because of the way grid works some extra properties are needed to instruct the browser not to place elements generated by Mendix in the grid layout.
.grid-table {
display: grid; // nested HTML elements should be layed out using grid
width: 100%; // the table should fill out all availble space of the parent element // definition of the number and size of columns
grid-template-columns: minmax(150px,15fr) minmax(100px,10fr) minmax(150px,15fr) minmax(100px,10fr) minmax(200px,20fr);
& .grid-table-row {
> div {
padding: 5px; // some padding for all columns
}
} & .grid-table-header > div {
position: sticky; top: 0; z-index: 999; // keep header visible while scrolling
font-weight: bold; background-color: lightgrey;// styling for header cells
} // do not place the below elements in the grid
& .mx-listview, .grid-table-row { display: contents;
> .mx-list { display: contents;
> .mx-listview-item { display: contents;
> .mx-dataview { display: contents;
> .mx-dataview-content { display: contents; }
}
}
}
}
}
As you can see here the table now re-scales gracefully without artifacts.
Summary
There are multiple ways to build a table in Mendix. When building simple CRUD pages for administrators, data grids are probably the best approach. However, when building user-facing tables I would suggest using a list view and CSS grid because of all the possibilities for customization. A sample implementation is available for download from the Mendix app store.
One final thing; grid is a fairly recent addition to CSS and not all grid concepts are supported by all browsers. This is important to keep in mind when deciding which approach to use.
Thank you for taking the time to read this post and I hope it helps you make great apps! This blog has originally been posted here.