Docs

Documentation versions (currently viewingVaadin 24)

Flow Integration

Integrating Flow components in Hilla views.

A Flow component can be used in Hilla views by implementing the WebComponentExporter class and using the resulting web component. The WebComponentExporter class can target any Flow component.

Here’s an example of such a component:

public class CustomComponent extends Div {

    public CustomComponent(@Autowired GreetService service) {
        Button button = new Button("Say hello", e -> {
            Notification.show("Hello!");
        });

        add(button);
    }
}

That component can then be turned into a web component like so:

public class MyFlowComponentExporter
        extends WebComponentExporter<CustomComponent> {

    public static final String TAG = "my-flow-component";

    public MyFlowComponentExporter() {
        super(TAG);
    }

    @Override
    protected void configureInstance(WebComponent<CustomComponent> webComponent,
                                     CustomComponent component) {
    }
}

For more information, see Creating an Embedded Vaadin Application.

Note
The WebComponentExporter needs to have a public no-argument constructor. Otherwise, it won’t be instantiated or generated.

To add the exported web component to a Hilla view, import the reactElement function from Flow and create a React.DOMElement with the same tag name as you used for the WebComponentExporter (i.e., TAG in the previous example) in a React component. Then use the resulting React component inside the view like this:

import { VerticalLayout } from '@vaadin/react-components/VerticalLayout';
import { reactElement } from 'Frontend/generated/flow/Flow'; 1

function MyFlowComponent() {
  return reactElement('my-flow-component'); 2
}

export default function HillaView() {
  return (
    <>
      <VerticalLayout className={'centered-content'}>
        <h3>Hilla View</h3>
        <MyFlowComponent/> // (3)
      </VerticalLayout>
    </>
  );
}
  1. Import the reactElement function.

  2. Return an instance of the custom element you exported, using the same tag name, from a React component.

  3. Use the React component in your view.

Using Attributes

You can add attributes for the element by passing in a Properties object with string value pairs to the reactElement function.

You can use this when the exported web component exposes properties to the client.

import { VerticalLayout } from '@vaadin/react-components/VerticalLayout';
import { reactElement } from 'Frontend/generated/flow/Flow';
import React from 'react';

function MyFlowComponent() {
  // Create element with property hellomsg
  return reactElement('my-flow-component', {
    hellomsg: 'Hi from the client!'
  });
}

export default function HillaView() {
  return (
    <>
      <VerticalLayout className={'centered-content'}>
        <h3>Hilla View</h3>
        <MyFlowComponent/>
      </VerticalLayout>
    </>
  );
}

You can also link the properties to the React component properties using a custom properties type:

import { VerticalLayout } from '@vaadin/react-components/VerticalLayout';
import { reactElement } from 'Frontend/generated/flow/Flow';
import React from 'react';

type MyProperties = {
  hellomsg: string
}

function MyFlowComponent(props: MyProperties) {
  // Create element with property hellomsg
  return reactElement('my-flow-component', {
    hellomsg: props.hellomsg
  });
}

export default function HillaView() {
  return (
    <>
      <VerticalLayout className={'centered-content'}>
        <h3>Hilla View</h3>
        <MyFlowComponent hellomsg={'Hi from the client!'}/>
      </VerticalLayout>
    </>
  );
}

In this way, changing the attribute also updates the web component property value.

The following example shows the corresponding server-side code for the web component property:

public class MyFlowComponentExporter
        extends WebComponentExporter<CustomComponent> {

    public static final String TAG = "my-flow-component";

    public MyFlowComponentExporter() {
        super(TAG);
        addProperty("hellomsg", "Hello!")
            .onChange(CustomComponent::setHelloMessage);
    }

    @Override
    protected void configureInstance(WebComponent<CustomComponent> webComponent,
                                     CustomComponent component) {
    }
}
public class CustomComponent extends Div {
    String helloMessage;

    public CustomComponent(@Autowired GreetService service) {
        Button button = new Button("Say hello", e -> {
            Notification.show(helloMessage);
        });

        add(button);
    }

    public void setHelloMessage(String helloMessage) {
        this.helloMessage = helloMessage;

    }
}

Onload Event for WebComponent

Loading the WebComponent script can take some time, depending on the network. Therefore, it might be good to show a loading indicator so the user knows to wait.

It’s possible to listen to the onload event for the WebComponent script so that the loading element can be removed when the script is finished loading.

The reactElement accepts an onload callback function as the third parameter. An onerror callback function can be set as the fourth parameter. If an onerror callback isn’t given, an error is logged into the console if a web component script fails to load.

import { VerticalLayout } from '@vaadin/react-components/VerticalLayout';
import { reactElement } from 'Frontend/generated/flow/Flow';
import React from 'react';

type MyProperties = {
  hellomsg: string
}

function MyFlowComponent(props: MyProperties) {
  // Create element with property hellomsg
  return reactElement('my-flow-component',
    undefined,
    () => document.getElementById('loading')?.remove()
  );
}

export default function HillaView() {
  return (
    <>
      <VerticalLayout className={'centered-content'}>
        <h3>Hilla View</h3>
        <!-- Placeholder element for MyFlowComponent script loading -->
        <div id={"loading"}>Loading script...</div>
        <MyFlowComponent hellomsg={'Hi from the client!'}/>
      </VerticalLayout>
    </>
  );
}

920dc03d-5eb4-4826-8934-4416b58a9a3e