Data Table - Small Screens
A table with several columns does not fit on a phone. The data table has a few options for narrow screens.
Sideways Scroll
By default, a table that is wider than the screen scrolls sideways inside its container. The page itself does not get wider.
Stacked Rows
With the stacked property, each row becomes a card when the screen is narrower than 920px. The header row is hidden, and the cells flow one after another in the card, each with its column title as a small label in front of the value.
Resize your browser window below 920px to see it in the example.
| Id | Name | Description | Actions |
|---|---|---|---|
| 1 | Superman | Journalist, reporter for the Daily Planet |
|
| 2 | Batman | Businessman, philanthropist, detective |
|
| 3 | Wonder Woman | Ambassador, curator of antiquities |
|
HTML:
<DataTable columns="$columns" items="$heroes" stacked remove (delete)="onDelete">
 <slotContent name="column_Id" data="$item">
 <td class="table-col-wide-only" data-label="Id">{$item->Id}</td>
 </slotContent>
 <slotContent name="column_Name" data="$item">
 <td class="table-stacked-main fw-semibold">{$item->Name}</td>
 </slotContent>
</DataTable>
PHP:
<?php

namespace ExamplesUi\Tables;

use ExamplesUi\HeroModel;
use Viewi\Components\BaseComponent;
use Viewi\UI\Components\Tables\TableColumn;

class TableStackedExample extends BaseComponent
{
 public array $columns = [];
 public array $heroes = [];

 public function init()
 {
 $this->columns = [
 // hidden between 920px and 1199px, the td gets the same class in the slot
 new TableColumn('Id', null, null, 'table-col-wide-only'),
 new TableColumn('Name'),
 new TableColumn('Description'),
 ];
 $this->heroes = [
 $this->makeHero(1, 'Superman', 'Journalist, reporter for the Daily Planet'),
 $this->makeHero(2, 'Batman', 'Businessman, philanthropist, detective'),
 $this->makeHero(3, 'Wonder Woman', 'Ambassador, curator of antiquities'),
 ];
 }

 public function makeHero(int $id, string $name, string $description): HeroModel
 {
 $hero = new HeroModel();
 $hero->Id = $id;
 $hero->Name = $name;
 $hero->Description = $description;
 return $hero;
 }

 public function onDelete(HeroModel $hero)
 {
 $this->heroes = array_values(array_filter($this->heroes, fn(HeroModel $h) => $h !== $hero));
 }
}
Labels
Cells rendered by the table get a data-label attribute with the column title, and the stacked layout shows it as the label. A column template component receives the title in its label property, see Defining Columns.
A cell from a column_{COLUMN_NAME} slot is your own td, so set data-label yourself. Without it, the cell has no label in the card.
Cell Classes
table-stacked-main - moves the cell to the top of the card at full width. Use it for the cells that name the row, like a title or a link.
table-stacked-actions - pushes the cell to the end of the last line of the card. The built-in edit and delete cell already has it.
Hiding a Column on Medium Screens
Between 920px and 1199px the table is still a grid, but it can be cramped. The table-col-wide-only class hides a column in this range only. Wider screens show it as a column, and stacked cards show it as a labelled field.
Pass the class as the cssClass of the column, so the header cell gets it, and add it to the td in the column slot:
new TableColumn('Id', null, null, 'table-col-wide-only')
<slotContent name="column_Id" data="$item">
 <td class="table-col-wide-only" data-label="Id">{$item->Id}</td>
</slotContent>
Long Values
For long values without spaces, such as URLs, two helper classes are available:
text-clamp-2 - cuts the text to two lines and allows it to break anywhere. Put it on an element inside the td, not on the td itself. Add a title attribute with the full text so the user can see it on hover.
cell-wide - gives the td a minimum width of 10rem, so the column is not squeezed to one character.
<slotContent name="column_Url" data="$item">
 <td class="cell-wide" data-label="Url">
 <a href="{$item->Url}" title="{$item->Url}" class="text-clamp-2">{$item->Url}</a>
 </td>
</slotContent>
Toolbar
Below 920px the search box and the toolbar buttons take a full row each, and the buttons are centered. This works without the stacked property.
Sticky Header
A long page of rows (50 or 100) pushes the column titles out of view. With the sticky property, the column titles stay at the top of the screen while the user scrolls the page. The head slot, the toolbar and the selection bar stay in view as well, above the column titles.
<DataTable columns="$columns" items="$items" sticky selectable paging />
Sticky works from 920px and wider. Below 920px the table behaves as if sticky is off.
If your page has its own fixed header, set the --data-table-sticky-top CSS variable to its height, so the table block stops under it:
<div style="--data-table-sticky-top: 56px">
 <DataTable columns="$columns" items="$items" sticky />
</div>
Use sticky for a table in the page itself. A table inside a scrolling panel or a modal has nothing to stick to.
Properties
stacked - (optional) shows each row as a card below 920px. Default: false.
sticky - (optional) keeps the column titles and everything above them in view while the page scrolls, from 920px and wider. Default: false.