Skip to main content

Mobile & responsive

Several nodes adapt to narrow screens. All of it is opt-in on the model and degrades gracefully without JavaScript.

Tables → stacked cards

Set stackOnMobile and a wide table becomes, on a narrow screen, one card per row with Column: value lines (the header row is hidden; each cell prints its column name):

UiTable.of("products", "Products")
.column(UiColumn.of("name", "Name"))
.column(UiColumn.of("price", "Price"))
.row(Map.of("id", "p1", "name", "Widget", "price", "€ 19.00"))
.stackOnMobile(true);

Live, in a frame deliberately kept below 640px — so the media query is in effect and you see the real thing, not a sketch of it:

The header row is gone; every cell prints its own column name.

Each <td> carries a data-label (the column label) that the CSS shows via a ::before, so it works in both the SSR and SPA output and needs no script.

Tabs → wrap or a "⋯ More" menu

Tab bars wrap onto more rows by default when they don't fit. For a single-row bar that collapses the overflow into a dropdown instead, set tabOverflow: MENU:

UiSection.of("main", null)
.section("overview", "Overview", overviewBody)
.section("orders", "Orders", ordersBody)
// …many tabs…
.tabOverflow(UiSection.TabOverflow.MENU);

It works out of the box: mount your page through a SuiEventBus and the tabs that don't fit collapse into a trailing dropdown on their own — it re-computes on resize. Without JS the bar simply wraps, so it stays usable either way.

const bus = new SuiEventBus(renderer, root);
renderer.mount(page); // tab overflow is handled automatically

The sidebar UiMenu has its own responsive story — a RESPONSIVE mode that is a push rail on desktop and an overlay drawer on mobile. See menu.


Do I still need the wire… helpers?

As a normal consumer — no. The SuiEventBus watches its root and runs these enhancers itself after every render, so tab overflow, menu-button popovers and the sidebar's persisted collapse state all just work once you've mounted through a bus.

The functions stay exported only as an escape hatch for the rare case of rendering without a bus — e.g. progressively enhancing a static, server-rendered page with a sprinkle of JS but no full SPA runtime. Then you'd call the one you need once after the markup is in the DOM. If you use the bus (the usual case), you can forget they exist.