Skip to content

How Mateu works

The shift Mateu requires is not technical — it is conceptual. You are not building screens. You are defining a model that becomes a UI.

Everything in Mateu maps to three things:

State — the fields that describe the current situation.

Actions — the methods that change it.

Structure — annotations that control layout, routing, navigation, and rendering behavior.

public class OrderEditor {
// state
String orderId;
OrderStatus status;
List<OrderLine> lines;
// action
@Button
public Message confirm() {
confirmOrderUseCase.handle(new ConfirmOrderCommand(orderId));
return new Message("Order confirmed");
}
}

That class is a complete UI definition. Mateu produces the form, the button, the validation, and the browser feedback from it.

Mateu works in three steps:

ViewModel (Java class)
-> UI definition (Mateu internal representation)
-> rendered UI (browser)

You only write the ViewModel. Mateu introspects its fields, methods, and annotations to produce a UI description. The renderer turns that description into a working browser interface.

Traditional frontend development starts with a page. You design the page, then you wire it to the backend.

In Mateu, you start with the model. The page is a consequence of the model, not the starting point.

When you need a product management screen, do not ask “what does this screen look like?” Ask “what is the state of a product, and what can you do with it?”

public record Product(
String id,
String name,
BigDecimal price,
ProductStatus status
) implements Identifiable {}

That question — answered in Java — is the UI definition.

@UI registers a class as a UI root at a given path. Mateu wires the routing automatically.

@UI("/products")
public class ProductsRoot { ... }

Fields on a ViewModel class become form fields. Their Java type determines the input:

Java typeDefault input
Stringtext field
int / Integernumber field
boolean / Booleancheckbox
LocalDatedate picker
LocalDateTimedate-time picker
enumselect / dropdown
List<T>grid or checkbox group

Override the default with @Stereotype.

Any method annotated with @Button becomes a clickable action. Returning a Message sends a browser notification. Returning any Java object navigates to it as a new view.

@Button
public Message submit() {
saveOrderUseCase.handle(command);
return new Message("Saved");
}

Actions belong to the backend. The button in the browser is just a signal — the backend decides what it means.

Mateu uses Bean Validation. Constraints are enforced in the browser before the action fires, and again on the backend.

@NotEmpty String name;
@Min(1) int quantity;
@Email String contactEmail;

A few annotations control how fields are arranged:

  • @Section("Shipping") — groups fields under a heading
  • @Colspan(2) — makes a field span two columns
  • @Zones / @Zone — side-by-side column layout
  • @Tabs / @Accordion — tabbed or collapsible groupings

@Menu exposes a field or nested class as a navigation entry. Nesting @Menu fields produces a tree.

@UI("/admin")
public class AdminRoot {
@Menu OrdersMenu orders;
@Menu ProductsMenu products;
}

@Lookup resolves foreign keys through backend suppliers — plain Java classes that can call any query service or repository.

@Lookup(search = ProductOptionsSupplier.class, label = ProductLabelSupplier.class)
String productId;

The browser does not know how to resolve the relationship. It asks the backend. The backend returns options. The browser displays them.

For standard business entities, AutoCrud gives you a full CRUD flow from a single class:

@UI("/orders")
public class Orders extends AutoCrud<Order> {}

When you need explicit control, Crud lets you define each screen separately:

public class OrdersOrchestrator extends Crud<
OrderView, OrderEditor, OrderCreationForm,
OrderFilters, OrderRow, String> { ... }

Mateu does not store UI state on the server between requests. Each browser interaction follows this path:

1. browser sends: current field values + action id
2. Mateu instantiates the ViewModel
3. Mateu hydrates it from the request
4. Mateu executes the action
5. Mateu serializes the result as a UI definition
6. browser renders the result

ViewModels are plain Java classes with no server-side lifecycle. They are created, used, and discarded per request.

ConceptHow
Statefields
Actionsmethods annotated @Button or @Toolbar
ValidationBean Validation (@NotEmpty, @NotNull, @Size, …)
Layout@Colspan, @Section, @Zones, @Tabs, @Accordion
Routing@UI, @Route
Navigation@Menu
Rendering intent@Stereotype
Relationships@Lookup
Dynamic rules@Rule, @Hidden
Browser feedbackreturn Message, navigate by returning any object
  • write HTML or JSX
  • configure frontend routes
  • write API clients
  • manage frontend state
  • duplicate validation
  • synchronize models across layers