> Markdown version of [Creating Java API for a Web Component](https://vaadin.com/docs/v10/flow/web-components/creating-java-api-for-a-web-component). Section index: [llms.txt](https://vaadin.com/docs/v10/flow/llms.txt)

# Creating Java API for a Web Component

The component class, e.g. `PaperSlider.java` you get when using the component starter, see [Integrating a Web Component](https://vaadin.com/docs/v10/flow/web-components/integrating-a-web-component.md) is just a stub which handles the imports. There are multiple ways to interact with a web component but the typical pattern is:

- Use properties on the element to define how it should behave

- Listen to events on the element to get notified of when the user does something

- Call functions on the element to perform specific tasks such as open a popup

- Add sub elements to define child contents

## <a id="setting-and-reading-properties"></a>Setting and reading properties

You can typically find out what properties an element supports from its JS docs, e.g. for paper-slider: <https://www.webcomponents.org/element/PolymerElements/paper-slider/elements/paper-slider>. The slider has a boolean property called `pin` which defines if "numeric value label is shown when the slider thumb is pressed". To create a `setPin(boolean pin)` Java API for this, you can add:

```java
public void setPin(boolean pin) {
    getElement().setProperty("pin", pin);
}
public boolean isPin() {
    return getElement().getProperty("pin", false);
}
```

The setter will now set the given property to the requested value and the getter will return the property value, or `false` as the default if the property has not been set (this should match the default of the web component property).

If you then update `DemoView`

```java
public DemoView() {
    PaperSlider paperSlider = new PaperSlider();
    paperSlider.setPin(true);
    add(paperSlider);
}
```

you will see the pin appear when dragging the slider knob.

While you can use the `getElement` methods directly like above, you will end up in defining the property in two places: the getter and the setter. To avoid repeating the property name and to be able to define all properties in one place, there is a `PropertyDescriptor` helper. Using `PropertyDescriptor` and the factory methods in `PropertyDescriptors`, you can define the `pin` property as a static field in the component and use the `PropertyDescriptor` in the getter and the setter:

```java
public class PaperSlider extends Component {

    private static final PropertyDescriptor<Boolean, Boolean> pinProperty = PropertyDescriptors.propertyWithDefault("pin", false);

    public void setPin(boolean pin) {
        pinProperty.set(this, pin);
    }

    public boolean isPin() {
        return pinProperty.get(this);
    }
}
```

The `pinProperty` descriptor here defines a property with the name `pin` and a default value of `false` (matches the web component) and both a setter and getter type of `Boolean` through generics (`<Boolean, Boolean>`). The setter and getter code then only invokes the descriptor with the component instance.

## <a id="synchronizing-the-value"></a>Synchronizing the Value

`paper-slider` is an input type component where the user can decide the what the value is. These kind of components should be integrated using the `HasValue` interface so they can automatically work in forms where you use `Binder`.

The value should be synchronized automatically from the client to the server, when the user changes it, and from the server to the client, when changing it form code. Additionally a value change event should be emitted on the server whenever the value changes. For the most common case where `getValue()` is based on a single element property, the `AbstractSinglePropertyField` base class can be used to take care of everything related to the value.

```java
public class PaperSlider extends AbstractSinglePropertyField<PaperSlider, Integer> {

    public PaperSlider() {
        super("value", 0, false);
    }

}
```

The type parameters define the component type (`PaperSlider`) returned by `getSource()` in value change events and the value type (`Integer`). The constructor parameters define the name of the element property that contains the value (`value`), the default value to use if there property isn’t set (`0`) and whether `setValue(null)` should be allowed or throw an exception (`false`, meaning that `null` is not allowed).

> **Note:** For more advanced cases that still rely on only one element property, there’s an alternative constructor for defining callbacks that convert between the low-level element property type and the high level `getValue()` type. For cases where the value cannot be derived based on a single element property, there’s a more generic `AbstractField` base class.

You can test this for instance as follows in the demo class:

```java
public DemoView() {
    PaperSlider paperSlider = new PaperSlider();
    paperSlider.setPin(true);
    paperSlider.addValueChangeListener(e -> {
        String message = "The value is now " + e.getValue();
        if (e.isFromClient()) {
            message += " (set by the user)";
        }
        Notification.show(message, 3000, Position.MIDDLE);
    });
    add(paperSlider);

    Button incrementButton = new Button("Increment using setValue", e -> {
        paperSlider.setValue(paperSlider.getValue() + 5);
    });
    add(incrementButton);
}
```

> **Note:** Some web components also update other properties that are not related to `HasValue`. [Creating A Simple Component Using the Element API](https://vaadin.com/docs/v10/flow/creating-components/tutorial-component-basic.md) describes how you can use the `@Synchronize` annotation to synchronize property values without automatically firing a value change event.

## <a id="listening-to-events"></a>Listening to Events

All web elements emit a `click` event when the user click on them. To allow the user of your component to listen to the `click` event, you can use a `ComponentEvent` together with the `@DomEvent` and `@EventData` annnotations:

```java
public Registration addClickListener(ComponentEventListener<ClickEvent> listener) {
    return addListener(ClickEvent.class, listener);
}
```

The `addListener` method in the super class will set up everything related to the event based on the annotations in the `ClickEvent` class that also need to be created:

```java
@DomEvent("click")
public class ClickEvent extends ComponentEvent<PaperSlider> {

    private int x,y;

    public ClickEvent(PaperSlider source, boolean fromClient, @EventData("event.offsetX") int x, @EventData("event.offsetY") int y) {
        super(source, fromClient);
        this.x = x;
    }
    public int getX() {
        return x;
    }
    public int getY() {
        return y;
    }
}
```

The `ClickEvent` uses `@DomEvent` to define the name of the DOM event to listen for, `click` in this case. Like all other events fired by a `Component`, it extends `ComponentEvent` which provides a typed `getSource()` method.

The click event defined above uses two additional constructor parameter annotated with `@EventData` to get the click coordinates from the browser. The expression inside the `@EventData` is evaluated when the event is handled in the browser and can access DOM event properties using a `event.` prefix and element properties using the `element.` prefix, e.g. `event.offsetX`.

Finally, you can test the event integration in the demo e.g. by adding to `DemoView.java`:

```java
paperSlider.addClickListener(e -> {
    Notification.show("Clicked at " + e.getX() + "," + e.getY(), 1000, Position.BOTTOM_START);
});
```

> **Note:** The two first parameters to a `ComponentEvent` constructor must be `PaperSlider source, boolean fromClient` which are filled automatically. Any `@EventData` parameters must be added after those and all additional parameters must have an `@EventData` annotation.

> **Tip:** The click event here is used as an example. You should use the `ClickEvent` already provided in Flow instead, which will provide even more information to the server.

> **Tip:** As the event data expression is evaluated as JavaScript, you can control propagation behavior using e.g. `@EventData("event.preventDefault()") String ignored`. Don’t do this. It ain’t right. But as long as there is no other API to control this, you can do this.

## <a id="calling-element-functions"></a>Calling Element Functions

In addition to properties and events, many elements offer methods which can be invoked for various reasons, e.g. `vaadin-board` has a `refresh()` method which is called whenever a change is made that the web component itself is not able to detect automatically. To call a function on an element, you can use the `callFunction` method in `Element`, e.g. to offer an API to the `increment` function on `paper-slider`, you could add to `PaperSlider.java`:

```java
public void increment() {
    getElement().callFunction("increment");
}
```

> **Tip:** In addition to the method name, `callFunction` takes an arbitrary number of parameters of certain supported types. Supported types are at the time of writing String, Boolean, Integer, Double, the corresponding primitive types, JsonValue, Element and Component references. See the method javadoc for more information about supported types.

You can test this by adding a call to `DemoView.java`:

```java
Button incrementJSButton = new Button("Increment using JS", e -> {
    paperSlider.increment();
});
add(incrementJSButton);
```

If you do this and added the value change listener described earlier, you will see that you get a notification with the new value after clicking on the button. The notification also indicates that the user changed the value because `isFromClient` checks that the change originates from the browser (as opposed to from the server) but does not differentiate between the cases when a user event changed the value and when a JavaScript call changed it.

> **Note:** This particular example is quite artificial as you are doing a server visit from a button click only to call a Javascript method on another element. It makes more sense if you call `increment()` from some other business logic.

## <a id="final-slider-integration-result"></a>Final Slider Integration Result

After doing the steps described above, you should end up with the following `PaperSlider` class:

```java
@Tag("paper-slider")
@HtmlImport("bower_components/paper-slider/paper-slider.html")
public class PaperSlider extends AbstractSinglePropertyField<PaperSlider, Integer> {

    private static final PropertyDescriptor<Boolean, Boolean> pinProperty = PropertyDescriptors.propertyWithDefault("pin", false);

    public PaperSlider() {
        super("value", 0, false);
    }

    public void setPin(boolean pin) {
        pinProperty.set(this, pin);
    }

    public boolean isPin() {
        return pinProperty.get(this);
    }

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

    public void increment() {
        getElement().callFunction("increment");
    }
}
```

This can now be further extended to support more configuration properties like `min` and `max`.

## <a id="add-sub-elements-to-define-child-contents"></a>Add Sub Elements to Define Child Contents

Some web components can contain child elements. If the component is a layout type where you just want to add child components, it is enough to implement `HasComponents`. The `HasComponents` interface provides default implementations for `add(Component…​)`, `remove(Component…)` and `removeAll()`. As an example, you could implement your own `<div>` wrapper as

```java
@Tag(Tag.DIV)
public class Div extends Component implements HasComponents {
}
```

You can then add and remove components using the provided methods, e.g.

```java
Div root = new Div();
root.add(new Span("Hello"));
root.add(new Span("World"));
add(root);
```

If you do not want to provide a public `add`/`remove` API, you have two options: use the Element API or create a new `Component` for encapsulating the internal element behavior.

As an example, say you wanted to create a specialized Vaadin Button which can only show a `VaadinIcon`. Using the available `VaadinIcon` enum, which lists the icons in the set, you can do e.g

```java
@Tag("vaadin-button")
@HtmlImport("bower_components/vaadin-button/vaadin-button.html")
public class IconButton extends Component {

    private VaadinIcon icon;

    public IconButton(VaadinIcon icon) {
        setIcon(icon);
    }

    public void setIcon(VaadinIcon icon) {
        this.icon = icon;

        Component iconComponent = icon.create();
        getElement().removeAllChildren();
        getElement().appendChild(iconComponent.getElement());
    }

    public void addClickListener(
            ComponentEventListener<ClickEvent<IconButton>> listener) {
        addListener(ClickEvent.class, (ComponentEventListener) listener);
    }

    public VaadinIcon getIcon() {
        return icon;
    }
}
```

The relevant part here is in the `setIcon` method. As there happens to be a feature in `VaadinIcon` which creates a component for a given icon (the `create()` call), it is used to create the child element. What remains is then to attach the root element of the child component, done using `getElement().appendChild(iconComponent.getElement());`.

In case the `VaadinIcon.create()` method was not available, you would have to resort to either creating the component yourself or using the element API directly. If you use the element API, the `setIcon` method might look something like:

```java
public void setIcon(VaadinIcon icon) {
    this.icon = icon;
    getElement().removeAllChildren();

    Element iconElement = new Element("iron-icon");
    iconElement.setAttribute("icon", "vaadin:" + icon.name().toLowerCase().replace("_", "-"));
    getElement().appendChild(iconElement);
}
```

The first part is the same but in the second part, the element with the correct tag name `<iron-icon>` is created manually and the `icon` attribute is set to the correct value, defined in `vaadin-icons.html`, e.g. `icon="vaadin:check"` for `VaadinIcon.CHECK`. The element is then attached to the `<vaadin-button>` element, after removing any previous content. With this approach you must also ensure that the `vaadin-button.html` dependency is loaded, otherwise handled by the `Icon` component class:

```java
@HtmlImport("bower_components/vaadin-button/vaadin-button.html")
@HtmlImport("bower_components/vaadin-icons/vaadin-icons.html")
public class IconButton extends Component {
```

Regardless of the approach taken, you can test the icon button as e.g.

```java
IconButton iconButton = new IconButton(VaadinIcon.CHECK);
iconButton.addClickListener(e -> {
    int next = (iconButton.getIcon().ordinal() + 1) % VaadinIcon.values().length;
    iconButton.setIcon(VaadinIcon.values()[next]);
});
add(iconButton);
```

This will show the `CHECK` icon and then change the icon on every click of the button.

> **Note:** You could extend `Button` directly instead of `Component` but then you would get all the public API of `Button` also
