Skip to content

Action Annotations

These annotations add interactive buttons and actions to pages, forms, and listings. They control where buttons appear, how they behave before executing (validation, confirmation), and what happens after they run.


Attaches a configurable action to a method. Repeatable via the @Actions container, so multiple @Action entries can stack on the same method.

@Repeatable(Actions.class)
@Retention(RetentionPolicy.RUNTIME)
public @interface Action {
String id() default "";
boolean background() default false;
boolean validationRequired() default false;
boolean confirmationRequired() default false;
boolean rowsSelectedRequired() default false;
String confirmationTitle() default "";
String confirmationMessage() default "";
String confirmationText() default "";
String confirmationDenialText() default "";
String modalStyle() default "";
String modalTitle() default "";
String customEventName() default "";
String customEventDetail() default "";
String href() default "";
String js() default "";
boolean sse() default false;
String fieldsToValidate() default "";
boolean bubble() default false;
}
AttributeTypeDefaultDescription
idString""Action ID. Auto-inferred from the method name when empty.
backgroundbooleanfalseRun the action without blocking the UI.
validationRequiredbooleanfalseValidate the form before executing.
confirmationRequiredbooleanfalseShow a confirmation dialog before executing.
rowsSelectedRequiredbooleanfalseRequire at least one row selected in a listing.
confirmationTitleString""Title shown in the confirmation dialog.
confirmationMessageString""Body text of the confirmation dialog.
confirmationTextString""Label for the confirm button.
confirmationDenialTextString""Label for the cancel button.
modalStyleString""Inline CSS applied to the confirmation modal.
modalTitleString""Title of the modal wrapper.
customEventNameString""Browser custom event to fire on completion.
customEventDetailString""Payload attached to the custom event.
hrefString""Navigate to this URL instead of calling a method.
jsString""Execute JavaScript on the client side.
ssebooleanfalseStream results to the UI via Server-Sent Events.
fieldsToValidateString""Comma-separated field IDs to validate (subset validation).
bubblebooleanfalseBubble the action result to the parent component.
public class OrderForm {
String orderId;
@Action(
validationRequired = true,
confirmationRequired = true,
confirmationTitle = "Delete order",
confirmationMessage = "This cannot be undone. Continue?",
confirmationText = "Delete",
confirmationDenialText = "Cancel"
)
void delete() {
orderRepository.delete(orderId);
}
}

@Action is most useful when combined with @Toolbar to place the button in a specific location on the screen.


Marks a field or method as a button rendered inline within the form body.

@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Button {}

No attributes. The button label is derived from the method or field name.

@UI("")
@Title("Simple Form")
public class SimpleForm {
@NotEmpty
String name;
@Button
public Message greet() {
return new Message("Hello " + name + "!");
}
}

Unlike @Toolbar, @Button places the button inside the form layout alongside the fields rather than in the toolbar strip at the top.


Marks a method to appear as a row-level action in a listing. The method receives the selected row as its parameter.

public @interface RowAction {}

No attributes. The action ID is derived from the method name.

public class InvoiceListing implements ListingBackend<Filters, InvoiceRow> {
@RowAction
void approve(InvoiceRow row) {
invoiceService.approve(row.id());
}
}

Row actions are displayed inside each row (for example as a dropdown or icon button) rather than in the page toolbar.


Marks a method as a toolbar button in a listing view. The method receives the list of currently selected rows. Both confirmationRequired and rowsSelectedRequired default to true, making this annotation safe by default.

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ListToolbarButton {
boolean confirmationRequired() default true;
boolean rowsSelectedRequired() default true;
}
AttributeTypeDefaultDescription
confirmationRequiredbooleantrueShow a confirmation dialog before executing.
rowsSelectedRequiredbooleantrueDisable the button until at least one row is selected.
Products.java
@UI("/products")
@Slf4j
public class Products extends AutoCrudOrchestrator<Product> {
@ListToolbarButton
void doSomethingOnRows(List<Product> selection) {
log.info("do something on {}", selection);
}
}

To skip confirmation or allow execution without row selection, set the corresponding attribute to false:

@ListToolbarButton(confirmationRequired = false)
public Object refresh(List<Grupo> selection) {
return Message.builder().text("Refreshed " + selection.size() + " items").build();
}

Marks a method as a toolbar button on a detail or editor screen.

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewToolbarButton {
boolean confirmationRequired() default true;
}
AttributeTypeDefaultDescription
confirmationRequiredbooleantrueShow a confirmation dialog before executing.
public class OrderDetailPage {
String orderId;
@ViewToolbarButton(confirmationRequired = false)
void printOrder() {
pdfService.print(orderId);
}
}

Places a method or field in the toolbar area of the current view. Combine with @Action to add fine-grained behaviour (validation, confirmation, etc.).

@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Toolbar {}

No attributes of its own.

CreateReleaseForm.java
@Toolbar
@Action(validationRequired = true)
Object create() {
var businessKey = UUID.randomUUID().toString();
return URI.create("/workflow/processes/" + businessKey + "?returnTo=/controlPlane/releases");
}

@Toolbar can also be placed on a field when the field holds a pre-built component that should appear in the toolbar.


Marks the final action in a multi-step wizard flow. When the annotated method is invoked, Mateu collects the state from all wizard steps before calling it.

@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface WizardCompletionAction {}

No attributes.

public class SetupWizard extends WizardOrchestrator {
StepOne stepOne;
StepTwo stepTwo;
StepThree stepThree;
@WizardCompletionAction
Object finish() {
setupService.apply(stepOne, stepTwo, stepThree);
return URI.create("/dashboard");
}
}

The framework calls the @WizardCompletionAction method only after all steps have been filled in. It is the last visible button rendered in the wizard navigation.


Action methods can return different types to drive the UI after execution:

Return typeEffect
void / nullNothing happens; the current view stays open.
A Java object or record (a form, a listing, etc.)Mateu navigates to that object as a new view.
URIThe browser navigates to the given URL.
MessageA toast notification is shown (Message.builder().text("...").build()).
// Navigate to a URL
Object create() {
return URI.create("/workflow/processes/" + UUID.randomUUID());
}
// Open another component
CreateReleaseForm createRelease(List<ChangeRow> selectedRows, HttpRequest httpRequest) {
return createReleaseForm.withUser(extractUser(httpRequest));
}
// Show a toast
@ListToolbarButton(confirmationRequired = false)
public Object refresh(List<Grupo> selection) {
return Message.builder().text("Refreshed " + selection.size() + " items").build();
}