Skip to content

Application shell

The application shell is the outer frame of your Mateu application: the navigation sidebar or tab bar, the logo, the title, and the top-level menu structure.

It is defined by the @UI class (declarative API) or the AppSupplier class (fluent API).


Annotate a class with @UI to make it the application root:

@UI("")
@Title("My Backoffice")
@PageTitle("My Backoffice — Admin")
@Logo("/images/logo.svg")
@FavIcon("/images/favicon.png")
public class MyApp {
@Menu
Products products;
@Menu
Orders orders;
@Menu
@EyesOnly(roles = "admin")
AdminPanel admin;
}

AnnotationEffect
@UI("path")Declares the app root and its base path ("" = root)
@Title("text")Heading shown in the app shell (sidebar or header)
@Subtitle("text")Subheading shown below the title
@PageTitle("text")Browser tab <title> tag
@Logo("/path")Logo image shown in the shell header
@FavIcon("/path")Browser favicon
@DrawerClosedStart with the navigation drawer collapsed
@Style("css")Inline CSS on the app container
@HomeRoute("/path")Default landing route when the app loads

Use AppSupplier + App.builder() for programmatic control:

@Route(value = "/admin", parentRoute = "")
public class AdminApp implements AppSupplier {
@Override
public App getApp(HttpRequest httpRequest) {
return App.builder()
.pageTitle("My Backoffice — Admin")
.title("My Backoffice")
.subtitle("Internal tools")
.logo("/images/logo.svg")
.favicon("/images/favicon.png")
.variant(AppVariant.MENU_ON_LEFT)
.homeRoute("/admin/home")
.menu(List.of(
new RouteLink("/home", "Dashboard"),
new RouteLink("/products", "Products"),
new RouteLink("/orders", "Orders"),
new Menu("/settings", "Administration", List.of(
new RouteLink("/users", "Users"),
new RouteLink("/config", "Configuration")
))
))
.build();
}
}
PropertyEffect
pageTitleBrowser tab title
titleHeading in the shell header
subtitleSubheading below the title
logoLogo image URL
faviconBrowser favicon URL
variantLayout variant (see below)
homeRouteDefault landing route
drawerClosedStart with drawer collapsed
styleInline CSS on the app container
cssClassesCSS class names on the app container

AppVariantNavigation position
TABSTab bar at the top (default)
MENU_ON_LEFTCollapsible sidebar on the left
MENU_ON_TOPHorizontal nav bar at the top

StyleConstants provides three ready-made style values:

import io.mateu.uidl.StyleConstants;
@Style(StyleConstants.CONTAINER) // max-width: 900px; margin: auto;
@Style(StyleConstants.FULL_WIDTH) // width: 100%;
@Style(StyleConstants.FULL_WIDTH_WITH_PADDING) // width: 100%; with side padding

Or use arbitrary CSS:

@Style("max-width: 1200px; margin: auto;")

In the fluent API, getApp() receives the HttpRequest, so branding can be dynamic:

@Override
public App getApp(HttpRequest httpRequest) {
String tenant = httpRequest.getHeaderValue("X-Tenant-Id");
TenantConfig config = tenantConfigService.get(tenant);
return App.builder()
.title(config.appName())
.logo(config.logoUrl())
.favicon(config.faviconUrl())
.variant(AppVariant.MENU_ON_LEFT)
.menu(buildMenu(config))
.build();
}

From an action, use UICommand to change the favicon or window title without a full reload:

// Change favicon from an action
return UICommand.builder()
.type(UICommandType.SetFavicon)
.data("/images/alert-favicon.png")
.build();
// Change window title from an action
return UICommand.builder()
.type(UICommandType.SetWindowTitle)
.data("(3 alerts) My Backoffice")
.build();

The @UI class can implement WidgetSupplier to render content in the main area when no sub-page is selected:

@UI("")
@Title("My Backoffice")
public class MyApp implements WidgetSupplier {
@Menu Products products;
@Menu Orders orders;
@Override
public List<Component> widgets(HttpRequest httpRequest) {
return List.of(
new Text("Welcome to the backoffice.")
);
}
}

For a full dashboard, return a BoardLayout with KPI cards and charts. See Dashboard home page.


Combine shell annotations with @KeycloakSecured and @EyesOnly:

@UI("")
@Title("My Backoffice")
@KeycloakSecured(
url = "https://auth.example.com/auth",
realm = "my-realm",
clientId = "my-client"
)
public class MyApp {
@Menu
Products products; // visible to all authenticated users
@Menu
@EyesOnly(roles = "admin")
AdminPanel admin; // only visible to admins
}

See Security for details.


  • Dashboard home page — build KPI cards, charts, and activity feeds as the landing page
  • Navigation and menus — declare menu entries, sub-menus, route links, and remote menus
  • Security@KeycloakSecured and @EyesOnly for authentication and role-based visibility