Overview

Responsive Mobile Layout

The framework automatically detects the viewport and changes the rendering of the two main components — <wuic-list-grid> and <wuic-parametric-dialog> (edit-form) — on narrow screens, without requiring changes to the application metadata.

What Changes on Mobile

ComponentDesktop (>768px)Mobile (≤768px)
<wuic-list-grid><p-table> with horizontal rows, frozen action column, tabular virtual scrollStack of vertical cards (one per record) with caption/value in two columns, action button on top, paginator at the bottom, optional PrimeNG virtual scroller
<wuic-parametric-dialog> (edit-form)Fields laid out on one or more columns according to mc_ui_size_widthFull-width fields stacked vertically, horizontally scrollable tab list, compressed toolbar

The switch is transparent to the application code: no host template to fork, no metadata to set. It reuses all existing metadata rules (mc_hide_in_list, mc_ui_grid_column_data_template, custom action button, conditional styling).

Configurable Threshold

The switch threshold defaults to 768px, aligned with the Bootstrap-like breakpoint. To change it in your host:

Snippet 1ts
// app bootstrap (e.g. main.ts or an APP_INITIALIZER)
import { MetadataProviderService } from 'wuic-framework-lib';
import { environment } from './environments/environment';

MetadataProviderService.widgetDefinition.mobileBreakpointPx =
  environment.mobileBreakpointPx ?? 768;

And in environment.ts:

Snippet 2ts
// src/environments/environment.ts
export const environment = {
  production: false,
  mobileBreakpointPx: 768  // tablet excluded
  // mobileBreakpointPx: 1024  // tablet portrait/landscape included
  // mobileBreakpointPx: 600   // only real smartphones
};

The threshold is read once in the constructor of the DeviceAwarenessService singleton. If you want to change it at runtime, recreate the instance by re-bootstrapping the app (rare use case).

Programmatic Detection

The DeviceAwarenessService singleton exposes:

  • isMobile$: Observable<boolean> — emits on every viewport transition (based on window.matchMedia)
  • isMobile: boolean — synchronous snapshot

Typical usage in a custom component:

Snippet 3ts
import { Component, inject } from '@angular/core';
import { AsyncPipe } from '@angular/common';
import { DeviceAwarenessService } from 'wuic-framework-lib';

@Component({
  selector: 'my-card',
  imports: [AsyncPipe],

Customizing the Mobile Card Template

The default mobile card shows actions + label/value rows. To provide a completely custom template (e.g. avatar + title + sub-info), set WidgetDefinition.mobileCardTemplate with an Angular markup string. The template is compiled at runtime via ɵcompileComponent, so it can use standard directives, pipes, and bindings.

Variables available in the template scope (passed as inputs by <wuic-list-grid> mobile):

  • rowData — current record
  • rowIndex — row index (0-based)
  • columns — array [{ field, header, metaColumn, ... }]
  • metaInfo — table meta info (metaInfo.tableMetadata, metaInfo.columnMetadata)
  • datasourceDataSourceComponent instance
  • actionButtonRowIsVisible(rowIndex) — boolean for virtualization (always true if not virtualized)

Example — two-row card with avatar and actions at the bottom:

Snippet 4ts
import { MetadataProviderService } from 'wuic-framework-lib';

MetadataProviderService.widgetDefinition.mobileCardTemplate = `
  <div class="my-mobile-card">
    <div class="my-mobile-card-header">
      <img *ngIf="rowData.avatar_url"
           [src]="rowData.avatar_url"

> Selector note: the template is rendered inside a host element with a custom selector <wuic-mobile-card-host> (not <div>) to avoid infinite loops on NgIf/ViewContainerRef. You don't need to manage it manually — just focus on the inner markup.

> Custom styles should be placed in global CSS (e.g. styles.scss) or in a component with encapsulation: ViewEncapsulation.None, because the card template is compiled into a component separate from the <wuic-list-grid> host. Alternatively, use wuic-mobile-card-* prefixed classes already styled by the library.

Customizing the Mobile Edit-form

The mobile edit-form is CSS-only (no alternative template): the rules under @media (max-width: 768px) in parametric-dialog.component.scss neutralize the inline width of fields and stack them vertically.

If you want a completely different mobile edit-form layout (e.g. multi-step wizard on mobile, single-page on desktop), you can use the existing md_edit_template system:

1. Create an Angular component with the desired markup and register it in the host widget map.

2. Set the md_edit_template column of _metadati__tabelle with the component's selector.

3. <wuic-parametric-dialog> renders it in place of the default generated form.

If you need to change the template only on mobile, use DeviceAwarenessService.isMobile inside the custom component to choose the variant.

Mobile Card Virtual Scroller

When the number of records per page is large, the mobile cards are rendered inside <p-virtualscroller> (selector alias of <p-scroller> PrimeNG 21). The switch is gated by the same isListVirtualizationEnabled() flag used by the desktop <p-table>, so:

  • Tables that have metaInfo.tableMetadata.archetypes.list.virtualize (or page size > 1000) activate virtualization on the mobile version as well.
  • The item height is estimated by getMobileCardEstimatedHeight() (heuristic on the number of visible columns + 18px gap), with [autoSize]="true" recomputing after the first render.

Nothing to configure on the app side: the same flag governs both modes.

Automatic Scroll-to-top

On mobile, after a page change from the paginator, the scroll automatically returns to the top of the card list (both the .wuic-mobile-card-list container and window). On desktop the default <p-table> behavior (internal table scroll) is unchanged.

Filter-bar on Mobile

<wuic-filter-bar> automatically changes behavior under the mobile threshold:

DesktopMobile
Inline collapsible panel (chevron). The content (5 tabs: Filter / Advanced Filter / Page Size / Sorting / Grouping + form) expands below the toggle, reducing the list area in the same flex container.Toggle button with pi-filter icon. The content opens in a modal `<p-dialog>` (95vw × 85vh) with dismissableMask, closeOnEscape, "Filter" header, and close button. The list below stays intact (the modal is an overlay) and when the user closes the dialog the app returns directly to the list without jumping to top.

Synchronized state: mobileDialogVisibleisCollapsed. Nothing to configure on the app side — the switch is transparent.

Architectural rationale: the flex chain .repeater-content > wuic-data-repeater > .data-repeater-body > wuic-list-grid-lazy > :host is all overflow: hidden + max-height: 100%. On narrow viewports, an inline panel that grows vertically squashes the list-grid to 0px, because the scrollable container (.repeater-content) is constrained to the viewport and cannot scroll to reveal the hidden list. The modal avoids the problem by moving the filter-bar out of the layout flow.

Best Practices

  • Keep the 768px threshold default if you have no precise needs: it's the most common standard value and already aligned with the breakpoint used by the framework's other @media rules.
  • When trying a custom card template, start from the default buildDefaultMobileCardTemplate (see list-grid source) and modify iteratively — reusing formatGridViewValue and <wuic-data-action-button-lazy> keeps consistency with desktop.
  • On mobile inline edit is not supported by design: clicking a card opens the edit-form. If you have a workflow that requires cell-by-cell editing even on mobile, consider a custom template that injects <wuic-field-editor-lazy> for editable fields.
  • Always test both viewports before closing a UI task: the resize between desktop and mobile must be smooth without reload (the isMobile$ subscription rebuilds the template automatically).

Screenshot

List grid mobile — card stack (cities)
List grid mobile — card stack (cities)
Carousel mobile — Upload Sample
Carousel mobile — Upload Sample
Chart mobile — radar (cities)
Chart mobile — radar (cities)
Kanban mobile — board scrolls horizontally
Kanban mobile — board scrolls horizontally
Map mobile — Google maps with markers
Map mobile — Google maps with markers
Scheduler mobile — month calendar (schedules)
Scheduler mobile — month calendar (schedules)