Build your own component with Vaadin Flow (Vaadin 14.5+)

The Vaadin 14.5 minor update backported Typescript configuration: You don’t need to do anything in your application to use Typescript instead of Javascript. That’s my favorite way to build custom component.

This chapter explains how to build a custom component and explain different ways to communicate between the backend and the frontend. It’s specific to Flow and does not work for Fusion.

Create a Typescript component

import {css, customElement, html, LitElement, property} from 'lit-element';

@customElement('my-test-component')
export class MyTestComponent extends LitElement {

    static get styles() {
        return css`
        :host {
            display: block;
        }
        `;
    }

    private $server?: MyTestComponentServerInterface;

    @property({ attribute: true })
    private test: String = "test";

    private clickAction() {
        this.$server!.displayNotification("Click on button");
    }

    private titleClickedEvent() {
        this.dispatchEvent(new CustomEvent('title-clicked', {
            // you can add detail: {kicked: true},
            cancelable: true
        }));
    }

    public replaceTestVariable(newValue: string) {
        this.test = newValue;
    }
    /**
     * Main method of the component
     *
     */
    render() {
        return html`<div>Test attribute ${this.test}</div>
        <div @click=${this.titleClickedEvent}>Title</div>
                    <div><button @click=${this.clickAction}>Call Notification</button></div>
        `;
    }

}

interface MyTestComponentServerInterface {
    displayNotification(text: string): void;
}

Create a Java component

@JsModule("./my-test-component.ts")
@Tag("my-test-component")
public class MyTestComponent extends Component {

    public MyTestComponent() {
    }

    public String getTest() {
        return getElement().getProperty("test");
    }

    public void setTest(String test) {
        getElement().setProperty("test", test);
    }

    @ClientCallable
    private void displayNotification(String text) {
        Notification.show("Notification: " + text);
    }

    public void replaceTestVariable(String newValue){
        getElement().callJsFunction("replaceTestVariable", newValue);
    }

    public Registration addTitleClickListener(ComponentEventListener<MyTestComponentClickEvent> listener) {
        return addListener(MyTestComponentClickEvent.class, listener);
    }

    @DomEvent("title-clicked")
    public static class MyTestComponentClickEvent extends ComponentEvent<MyTestComponent> {

        public MyTestComponentClickEvent(MyTestComponent source, boolean fromClient) {
            super(source, fromClient);

        }
    }
}

@JsModule is loading the file and add the content in the Vaadin bundle but doesn’t load the component. Inside the web component, you define a new custom element in the browser CustomElementRegistry with @customElement('my-test-component'). (The annotation is Typescript specific)

The @Tag will load the component defined in the CustomElementRegistry.

Warning

Always name your tag with a dash - inside, you can’t name it mytestcomponent it won’t be accepted by the browser.

How to send data to the frontend?

Attributes

On the client side you can add attributes or properties that are listened

Execute Javascript or call javascript function

How to send data to the backend?

$server and ClientCallable

When the component is bound to the backend, Flow instantiates a variable $server. It helps to call all the Java methods @ClientCallable from the frontend.

With TypeScript

Event

You can send an event on the