Renderers

This section describes how to customize the rendering of UI components like comboBox, dataGrid, checkboxGroup, select and others using custom renderers in Jmix. Custom renderers allow developers to control the visual representation of data within these components, tailoring the UI to specific application requirements. This is particularly useful for:

  • Enhanced visual representation: They enable the inclusion of visual elements beyond plain text, such as icons, images, progress bars, or others, to make data more easily understandable and engaging. This can improve the overall user experience and clarity of the UI.

    radio button group renderer
  • Conditional rendering: Renderers can implement logic to change the visual appearance based on the data’s value or other contextual information. For instance, a renderer might display a green checkmark for successful records and a red checkmark for failed ones.

    renderer 2
  • Complex layouts: For situations requiring more complex visual layouts than the default rendering offers, custom renderers provide the flexibility to arrange and display data in non-standard ways. This could involve combining several UI elements within a single component cell or creating entirely custom layouts.

    renderer 3

In essence, renderers in Jmix empower developers to move beyond the basic display capabilities of the default UI components, creating a more tailored and user-friendly interface that effectively communicates data to the end-user.

If you need to simply format data (for example, change the way a date or number appears), use a formatter.

Predefined XML Renderer

Jmix provides predefined XML renderers for DataGrid and TreeDataGrid columns to simplify common formatting and display table data:

They accept a format string. For example:

<column property="joiningDate">
    <localDateRenderer format="MMM dd, yyyy"/>
</column>

To add a renderer in Jmix Studio, select the column element in the view descriptor XML or in the Jmix UI structure panel and click on the Add→<Some>Renderer button in the Jmix UI inspector panel.

Component Renderer

Component renderers provide a mechanism for rendering data within UI components using other UI components.

A component renderer takes data as input and generates a UI component (such as a checkBox, or image) to represent that data. This generated component is then used by the parent UI component (for example, a dataGrid column) to display the data. This approach is particularly useful when you need to visually represent data using more than just simple text formatting.

While simple to implement, component renderers can negatively impact performance, especially with large datasets, because they create a separate UI component for each data item.

To create a renderer use the setRenderer() method or @Supply annotation.

To generate a renderer handler method in Jmix Studio, select the component or grid column, go to the Handlers tab of the Jmix UI inspector panel and double-click the relevant row. Also, you can use the Generate Handler action available in the top panel of the view class and through the Code → Generate menu (Alt+Insert / Cmd+N).

As an example, let’s consider adding a renderer to display a boolean value using a checkBox in a dataGrid.

Select the active column, switch to the Handlers tab of the Jmix UI inspector and double-click the renderer handler method:

renderer 1

Implement the dataGridCheckboxActiveRenderer method:

@Supply(to = "dataGridCheckbox.active", subject = "renderer")
private Renderer<User> dataGridCheckboxActiveRenderer() {
    return new ComponentRenderer<>(
            () -> {
                JmixCheckbox checkbox = uiComponents.create(JmixCheckbox.class); (1)
                checkbox.setReadOnly(true); (2)
                return checkbox; (3)
            },
            (checkbox, user) -> checkbox.setValue(user.getActive()) (4)
    );
}
1 The JmixCheckbox component instance is created using the UiComponents factory.
2 Sets checkbox to read-only mode, preventing users from directly changing its state.
3 The renderer returns the newly created, read-only checkbox to be shown in the column cells.
4 Lambda expression that configures the checkbox’s value. It’s a consumer that takes two parameters: the checkbox component and a User instance. It sets the checkbox’s value based on the active attribute of the User entity.
renderer 4

Examples of custom rendering for various UI components are provided in the relevant sections of the Jmix documentation:

LitRenderer

LitRenderer renders content using HTML and Lit’s data-binding syntax; it’s more lightweight than component-based renderers.

LitRenderer allows you to define an HTML template and bind properties from an entity to template variables:

@Supply(to = "dataGridLit.userInfo", subject = "renderer")
private Renderer<User> dataGridLitUserInfoRenderer() {
    return LitRenderer.<User>of("${item.firstName}<br>${item.lastName}<br>${item.email}")
            .withProperty("firstName", User::getFirstName)
            .withProperty("lastName", User::getLastName)
            .withProperty("email", User::getEmail);
}
renderer 5
LitRenderer renders efficiently and is ideal for high-performance applications needing frequent updates. Its lightweight design makes it well-suited for applications with many components or dynamic content.

You can use LitRenderer in the following UI components:

Fragment Renderer

Renderers for virtualList, dataGrid and other components can be defined using fragments. A special fragmentRenderer XML element is used to declaratively describe a renderer.

Like regular fragments, a fragmentRenderer is defined using a descriptor and a Java controller.

  1. Create FragmentRenderer XML-descriptor

    The descriptor can contain an optional instanceContainer for the entity that will be used by the renderer.

    <fragment xmlns="http://jmix.io/schema/flowui/fragment">
        <data>
            <instance id="userDc" class="com.company.onboarding.entity.User">
                <loader id="userDl"/>
                <fetchPlan extends="_base"/>
            </instance>
        </data>
        <content>
            <hbox>
                <icon icon="ANGLE_DOUBLE_RIGHT"/>
                <formLayout id="form" dataContainer="userDc">
                    <textField property="username" readOnly="true"/>
                    <textField property="firstName" readOnly="true"/>
                    <textField property="lastName" readOnly="true"/>
                    <textField property="email" readOnly="true"/>
                </formLayout>
            </hbox>
        </content>
    </fragment>
    If the instance container is not defined, you can use the FragmentRenderer.getItem() method to handle rendering.
  2. Create FragmentRenderer Java Controller

    The fragment renderer class should extend the FragmentRenderer base class with type parameters indicating the root component and rendered entity, for example:

    @FragmentDescriptor("user-fragment.xml") (1)
    @RendererItemContainer("userDc") (2)
    public class UserFragment extends FragmentRenderer<HorizontalLayout, User> {
    }
    1 The @FragmentDescriptor annotation specifies a string value that is a path to an XML file which is used for the fragment initialization.
    2 The @RendererItemContainer annotation is used to specify the data container that accepts the rendered entity.
  3. Use FragmentRenderer in a View

    Select the component where you want to render items and include the fragmentRenderer element. This element requires a class attribute specifying the fully qualified name (FQN) of a class extending the abstract io.jmix.flowui.fragmentrenderer.FragmentRenderer class.

    <virtualList itemsContainer="usersDc">
        <fragmentRenderer
                class="com.company.onboarding.view.component.virtuallist.UserFragment"/>
    </virtualList>

    To add a fragmentRenderer in Jmix Studio, select the UI component in the view descriptor XML or in the Jmix UI structure panel and click on the Add→FragmentRenderer button in the Jmix UI inspector panel.

    The fragmentRenderer element also supports loading properties, just like the fragment element.

renderer 6

You can use fragmentRenderer in the following UI components: