Creation of a UI with linkki

PresentationModelObject with @UISection

When a class is annotated with @UISection, linkki takes control over the creation and arrangement of the defined components. Using annotations for the UI elements, certain aspects can be defined or controlled. The sections are created via a PmoBasedSectionFactory.

The UI elements are bound either to the 'properties' of a ModelObject or a PMO. A detailed description can be found in the chapter Data on Multiple Layers.

In all cases, if the ModelObject or PMO doesn’t have a corresponding setter, the field is readOnly.

In the first section the creation of a section for a 'standard' form is exemplified. In the second section the creation of a section with a table is detailed.

The annotation @UISection can be omitted. The SectionCreationContext created for a PMO class without that annotation treats that class as having a @UISection annotation with default values.

Binding of a Form

Binding with @ModelObject
public class ContactSectionPmo {

    private Contact contact;
    public Contact getContact() {
        return contact;

    @BindTooltip(tooltipType = TooltipType.DYNAMIC)
    @UITextField(position = 10, label = "Firstname", required = RequiredType.REQUIRED, modelAttribute = Contact.PROPERTY_FIRSTNAME)
    public void firstname() {
        /* model binding only */

    public String getFirstnameTooltip() {
        return "First name";

    @BindTooltip(tooltipType = TooltipType.DYNAMIC)
    @UITextField(position = 20, label = "Lastname", required = RequiredType.REQUIRED, modelAttribute = Contact.PROPERTY_LASTNAME)
    public void lastname() {
        /* model binding only */

    public String getLastnameTooltip() {
        return "Last name";

    @UIRadioButtonGroup(position = 30, label = "Gender", buttonAlignment = AlignmentType.HORIZONTAL, content = AvailableValuesType.ENUM_VALUES_EXCL_NULL, //
            itemCaptionProvider = GenderCaptionProvider.class)
    public void gender() {
        /* model binding only */

    @UIComboBox(position = 40, label = "Country of Birth", //
            content = AvailableValuesType.DYNAMIC, itemCaptionProvider = ToStringCaptionProvider.class, //
            modelAttribute = Contact.PROPERTY_COUNTRY_OF_BIRTH)
    public void countryOfBirth() {
        /* model binding only */

    public List<String> getCountryOfBirthAvailableValues() {
        return Arrays.asList(Locale.getAvailableLocales()).stream()
                .map(l -> l.getDisplayCountry(UiFramework.getLocale()))

    @UICheckBox(position = 50, caption = "Add to favorites")
    public void favorite() {
        /* model binding only */

The definition of modelAttribute is optional if the property name in the ModelObject and the name of the annotated method are equal. But it is recommended to specify the modelAttribute to make it explicit. The value should be externalized to a constant in the target model object as seen for the lastname property.

Binding of a Table

To create a section with a table the PMO class must implement org.linkki.core.defaults.columnbased.pmo.ContainerPmo<ROW>. The generic parameter ROW represents the type of the PMO to create a row in this table.

public class ContactTablePmo implements ContainerPmo<ContactRowPmo> {

The method getItems() returns the rows of the table in the form of the previously defined ROW 'row PMOs'.

    public List<ContactRowPmo> getItems() {
        return items.get();

In the interface ContainerPmo<ROW> additional default methods are defined. A detailed description can be found in the section about ContainerPmo.

The so called 'Row PMO' is a regular PMO as described in the first section. The only difference is that the UI elements may optionally be annotated with @UITableColumn.

    @UITableColumn(expandRatio = 1F)
    @UILabel(position = 10, label = "Name")
    public String getName() {
        return contact.getName();

All UI elements can be used in tables. The binding of a @UIButton looks as follows:

    @UITableColumn(width = 50)
    @UIButton(position = 30, icon = VaadinIcons.EDIT, showIcon = true)
    public void edit() {
In our example the elements of the table shall be presented as read-only. Therefore no direct binding of the ModelObject via the @ModelObject annotation is done. If the items of your table are provided from a model object you may consider to use org.linkki.core.defaults.columnbased.pmo.SimpleTablePmo<MO, ROW> which is described in chapter Tables in detail.