Table of contents
1.
Introduction
2.
What is a Component?
3.
Single Element
3.1.
Inserting an API
3.2.
Default Disabled Behavior Overriding
4.
Multiple Element
4.1.
Inserting an API
5.
Using API Helpers to Define Component Properties
5.1.
Interface PropertyDescriptor
6.
Using Existing Components
6.1.
Example
6.2.
Inserting an API
7.
Extending Components
7.1.
Extending a Component Implementing Server-Side Approach
7.2.
Adding to a Component Employing a Client-Side Approach
8.
Using Events
8.1.
Establishing an Event
8.2.
Event Listener Definition
8.3.
Triggering Events from the Server
8.4.
Triggering Events from the Client
9.
Component Containers
9.1.
Implementing a Custom Add Method
9.2.
Child components being attached to the DOM
9.3.
Utilizing Methods for Component Hierarchy
9.4.
Enabled and Disabled Container Components
10.
Frequently Asked Questions
10.1.
What are the components of Vaadin?
10.2.
What is the relation between GWT and Vaadin?
10.3.
When was Vaadin discovered?
10.4.
Why is Vaadin beneficial?
10.5.
What distinguishes an element from a component?
11.
Conclusion
Last Updated: Mar 27, 2024

Creating Components

Author Aditya Kumar
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

Vaadin Flow allows for the creation of components in numerous ways. This article shows how to create a simple component using the element API, a component with many elements, a component using another component, a component container, and extending a component, among other methods.

Creating components in Vaadin

Polymer templates can be used to generate components as well. Additionally, we will cover relevant topics when constructing components by utilizing events with components, using component lifecycle callbacks, and implementing Vaadin mixin interfaces.

What is a Component?

A component-based framework is Vaadin Flow. Several components, including Grid, TextField, and VerticalLayout, have previously been used by you. However, the freedom to design your components is where the actual strength of the component-based architecture lies.

Your view can be divided into smaller components; each takes care of a distinct aspect of the view rather than being built entirely in a single class. This method can make individual components simpler to comprehend and verify. The fundamental purpose of the top-level view is to coordinate the components.

For creating components there are different ways which are mentioned below:

  • Single Element
  • Multiple Elements
  • Using API Helpers to Define Component Properties
  • Using Existing Components
  • Extending Components
  • Using Events
  • Component Containers
     

Let's discuss all creating components which are mentioned above one by one in a detailed manner.

Single Element

This is the first method for creating components. We will show how to create a component in this section using the Element API and a single DOM element.

Example

Converting an <input> element into a TextField component.

@Tag("input")
public class TextField extends Component 
{
    public TextField(String val) 
    {
        getElement().setProperty("value",val);
    }
}
You can also try this code with Online Java Compiler
Run Code


The root element is:

  • Based on the @Tag annotation, which was automatically created (by the Component class).
  • Utilising the getElement() function to access.
  • Used to establish the field's starting value.
     

In the @Tag annotation, predefined constants are usable. The @Tag("enter") annotation, for instance, is identical to @Tag (Tag.ENTER). Most tag names, but not all, have constants.

Inserting an API

You can include an API to retrieve and set the value to simplify the component.

As an example, use the @Synchronize annotation to add an API.

@Synchronize("change")

public String getValue() 
{
    return getElement().getProperty("value");
}

public void setValue(String val) 
{
    getElement().setProperty("value", val);
}
You can also try this code with Online Java Compiler
Run Code


The getter's @Synchronize annotation ensures that the browser notifies the server when a property changes.

The annotation specifies the name of the DOM event—in this case, a change event—that starts synchronization.

The updated value attribute, which can be inferred from the getter name, is transmitted to the server whenever the input element is modified.

The @Synchronize annotation can override the property name and specify multiple events if necessary.

Only events that come from or bubble to the root element are mapped by the annotation @Synchronize. For instance, @Synchronize only maps events from the div element if you have an input element inside of it.

Default Disabled Behavior Overriding

All components that implement the HasEnabled interface can use the setEnabled function.

All components that implement the ‘HasValue’, ‘HasComponents’, or ‘Focusable’ interfaces can also use the setEnabled function.

A disabled attribute is automatically added to the client element when a component is disabled. By overriding the Component:onEnabledStateChanged(boolean) method, you can change this.

To update elements in a component that needs a unique disabled marking, override the default disabled behavior.

@Override
public void onEnabledStateChanged(boolean enabled) 
{
    setDisabled(!enabled);
    refreshButtons();
}
You can also try this code with Online Java Compiler
Run Code

Multiple Element

The creation of a component utilizing the Element API and several DOM elements is demonstrated in this section. We build a label-supporting TextField component.

Example

Component's DOM structure.

<div>
    <label></label>
    <input>
</div>


Example of TextField component with the elements "input" and "label"

@Tag("div")
public class TextField extends Component {

    Element lElement = new Element("label");
    Element iElement = new Element("input");

    public TextField() {
        iElement.synchronizeProperty("value", "change");
        getElement().appendChild(lElement, iElement);
    }
}
You can also try this code with Online Java Compiler
Run Code

 

  • The DOM structure is established by designating the root element as an <div> in the @Tag annotation.
  • The root element is followed by the label and input elements.
  • The input element is used to configure value synchronization.

Inserting an API

You can include an API to set the input value and label text, making the component simpler.

An example would be the addition of an API to retrieve and modify values for input and label elements.

public String getLabel() 
{
	return lElement.getText();
}

public String getValue() 
{
	return iElement.getProperty("value");
}

public void setLabel(String l) 
{
	lElement.setText(l);
}

public void setValue(String val) 
{
	iElement.setProperty("value", val);
}
You can also try this code with Online Java Compiler
Run Code

Using API Helpers to Define Component Properties

This is one of the most important methods of creating components. Managing characteristics and properties in a component are made more accessible by the PropertyDescriptor interface (and related PropertyDescriptors helper class).

Use the descriptor from the setter and getter methods after using PropertyDescriptors to declare the property name and default value all in one place.

Example

Specifying the default property value using the propertyDescriptors.propertyWithDefault method.

@Tag("input")
public class TextField extends Component 
{
    private static PropertyDescriptor<String, String> VAL = PropertyDescriptors.propertyWithDefault("value", "");

    public String getValue() 
    {
        return get(VAL);
    }

    public void setValue(String values) 
    {
        set(VAL, values);
    }
}
You can also try this code with Online Java Compiler
Run Code


For your component API to work properly for a certain property, such as the value of an input field:

  • The same property or attribute should be used by the getter and setter.
  • It is important to handle the default value properly.
  • Either of these should be the getter's return value:
    • The type of the setter's input value, such as a String, or
    • The setter's type can also be optional if the property is not required.
       

The aforementioned is automatically taken into account by property descriptors.

Interface PropertyDescriptor

The assistance methods offered by the PropertyDescriptors class are used to generate PropertyDescriptor objects.

Depending on how you want your component to function, a variety of helper methods are available:

  • An element property with a specified default value is represented by PropertyDescriptors.propertyWithDefault.
     
  • An element attribute with a specified default value is mapped by PropertyDescriptors.attributeWithDefault.
     
  • When the default value is set, PropertyDescriptors.optionalAttributeWithDefault returns an empty Optional instead of mapping to an element attribute with the default value.
     

Example of applying the PropertyDescriptors.optionalAttributeWithDefault method to a TextField's optional placeholder.

@Tag("input")
public class TextField extends Component 
{
    private static PropertyDescriptor<String, Optional<String>> PLCHOLDER = PropertyDescriptors.optionalAttributeWithDefault("placeholder", "");

    public Optional<String> getPlaceholder() 
    {
        return get(PLCHOLDER);
    }

    public void setPlaceholder(String pholder) {
        set(PLCHOLDER, pholder);
    }
}
You can also try this code with Online Java Compiler
Run Code


When the attribute or property is not set, the default value used in all PropertyDescriptors methods should coincide with the value displayed in the browser. If not, the value won't be accurately delivered to the browser when the user sets the value to the default value.

Using Existing Components

This section shows how to build a Composite component out of pre-existing parts.

By integrating preexisting Div, Label, and Input HTML components into this hierarchy, we may construct a TextField component:

Div

  • Label
  • Input
     

In this case, the appropriate course of action is to base the component on a Composite. Although it is possible to construct a new component by extending the Div HTML component, doing so is not recommended because it exposes Div API functions like add(Component) to the user unnecessarily.

Example

Extending Composite <Div> to create a TextField component.

public class TextField extends Composite<Div> 
{
    private Label l;
    private Input i;

    public TextField(String lText, String val) 
    {
        l = new Label();
        l.setText(lText);
        i = new Input();
        i.setValue(val);

        getContent().add(l, i);
    }
}
You can also try this code with Online Java Compiler
Run Code

 

  • The root component is created automatically by the Composite (provided using the generic (Composite<Div>)).
  • The getContent() method makes the root component available.
  • Only the child components must be created and added to the root Div in the constructor.
  • The setValue method in the Input component is used to set the value.

Inserting an API

By delegating to the Input and Label components, you may add an API to the component to get and set the value and label text.

The label and value can be set and retrieved using an API.

public String getValue() {
    return i.getValue();
}
public void setValue(String val) {
    i.setValue(val);
}

public String getLabel() {
    return l.getText();
}
public void setLabel(String lText) {
    l.setText(lText);
}
You can also try this code with Online Java Compiler
Run Code


The public API exposes only the defined methods and a few generic methods defined in the Component interface.

Employing a Component (instead of an Element) or a Composite adds to the browser's overhead.

Extending Components

Any current component can be extended to create a new component.

There is often a client-side component and a corresponding server-side component for each component:

  • Client-side component: Consists of HTML, CSS, and JavaScript and specifies the number of properties that control how the component functions on the client.
     
  • Server-side component: The component is managed on the server side by Java code that controls client-side properties and behavior.
     

Both the client and server sides can be used to extend a component. Please note that these are competing strategies that cannot be used together.

This section shows you how to modify the prebuilt text field component using two distinct methods.

Extending a Component Implementing Server-Side Approach

Extending a server-side component can be helpful when you wish to add new functionality (as opposed to visual features) to an existing component. For instance, you might use this method when automatically processing data, adding default validators, or integrating several simple components into a field that manages complicated data.

Consider making your component a web component and wrapping it if it has a lot of logic that could be done more easily on the client side. This strategy might improve the user experience while reducing the server burden.

Extending the TextField component in this example, we produce a NumericField component. The user can modify the default number in the new component using the + and - controls.

Example

Consider extending the TextField component to create a NumericField component.

@CssImport("./styles/numeric-field-styles.css")
public class NumericField extends TextField 
{
    private Button subsBtn;
    private Button aBtn;

    private static final int DEFAULT_VALUE = 0;
    private static final int DEFAULT_INCREMENT = 1;

    private int numValue;
    private int increValue;
    private int decreValue;

    public NumericField() 
    {
        this(DEFAULT_VALUE, DEFAULT_INCREMENT, -DEFAULT_INCREMENT);
    }

    public NumericField(int val, int increValue, int decreValue) 
    {
        setNumericValue(val);
        this.increValue = increValue;
        this.decreValue = decreValue;

        setPattern("-?[0-9]*");
        setPreventInvalidInput(true);

        addChangeListener(event -> {
            String text = event.getSource().getValue();
            if (StringUtils.isNumeric(text)) {
                setNumericValue(Integer.parseInt(text));
            } else {
                setNumericValue(DEFAULT_VALUE);
            }
        });

        subsBtn = new Button("-", event -> {
            setNumericValue(numalue + decreValue);
        });

        aBtn = new Button("+", event -> {
            setNumericValue(numValue + increValue);
        });

        getElement().setAttribute("theme", "numeric");
        styleBtns();

        addToPrefix(subsBtn);
        addToSuffix(aBtn);
    }

    private void styleBtns() 
    {
        subsBtn.getElement().setAttribute("theme", "icon");
        aBtn.getElement().setAttribute("theme", "icon");
    }

    public void setNumericValue(int val) 
    {
        numValue = val;
        setValue(val + "");
    }
}
You can also try this code with Online Java Compiler
Run Code


Alternately, you can add functionality to the Composite class, which has a simple API. When your custom component extends the implementation of the Component, the more extensive API is revealed and thus hides the methods that are accessible in it.

Adding to a Component Employing a Client-Side Approach

Client-side components for Vaadin are built using Polymer 3, which allows for a component extension. Existing Polymer elements can be extended using the extends attribute.

A template can be inherited from another Polymer element in five different ways:

  • Taking a base class template and not changing it.
  • A child class's overriding of a base class's template.
  • The alteration of a superclass template copy.
  • Extending a child class's base class template.
  • Provide template-extension points for material from a child class in a base class.

Using Events

In this section, we will be creating components by using events. The event bus offered by the Component base class can be used by your component class's event-handling API.

The event bus accommodates:

  • Extending ComponentEvent is event classes, and
  • ComponentEventListener<EventType> type listeners for events.

Establishing an Event

Your event must extend ComponentEvent to use the event bus. The type of the component that fired the event is parameterized into the base type. As a result, the getSource() method always returns the appropriate component type.

The second constructor parameter determines the event's trigger—a DOM event in the browser or the component's server-side API.

An example would be to extend ComponentEvent to create an event.

public class ChangeEvent extends ComponentEvent<TextField> 
{
    public ChangeEvent(TextField s, boolean fClient) 
    {
        super(s, fClient);
    }
}
You can also try this code with Online Java Compiler
Run Code

Event Listener Definition

It is not essential to designing a unique interface for your event type because event listeners are of the generic ComponentEventListener<EventType> type.

A handle that may be used to remove the listener is also returned by the method for creating a listener. Consequently, a separate method to remove an event listener does not need to be implemented.

Example

Adding an event listener using the addChangeListener() function.

@Tag("input")
public class TextField extends Component {
    public Registration addChangeListener(ComponentEventListener<ChangeEvent> listen) {
        return addListener(ChangeEvent.class, listen);
    }

    // Other component methods omitted
}
Changing the event listeners:
TextField tField = new TextField();
Registration reg = tField.addChangeListener(e ->
                System.out.println("Event fired right now!"));
reg.remove();
You can also try this code with Online Java Compiler
Run Code

Triggering Events from the Server

You can trigger an event on the server by creating the event object and providing it to the fireEvent() method. To indicate that the event is not client-generated, use false as the second constructor parameter.

Example

To fire an event from the server, use the fireEvent() function with the false argument.

@Tag("input")
public class TextField extends Component 
{
    public void setValue(String val) 
    {
        getElement().setAttribute("value", val);
        fireEvent(new ChangeEvent(this, false));
    }

    // Other component methods omitted
}
You can also try this code with Online Java Compiler
Run Code

Triggering Events from the Client

A component event can be linked to a DOM event that the browser's element fires.

To do this, you must specify the name of the DOM event to listen to using the @DomEvent annotation in your event class. Vaadin Flow automatically adds a DOM event listener to the element when a component event listener is available.

For example, consider connecting a TextField component to a DOM event using the @DomEvent annotation.

@DomEvent("change")
public class ChangeEvent extends ComponentEvent<TextField> {
    public ChangeEvent(TextField s, boolean fClient) {
        super(s, fClient);
    }
}
You can also try this code with Online Java Compiler
Run Code

Component Containers

In this section, we will be creating components container.

An additional component can be added to a component container. A general public API is generally used to create containers.

Example

Simple component container.

@Tag("div")
public class MyComponentContainer extends Component implements HasComponents {
}
You can also try this code with Online Java Compiler
Run Code


The MyComponentContainer root element (in this example, “div”) can be attached to component elements using the add(Component...) and remove(Component...) methods of the HasComponents interface.

Implementing a Custom Add Method

You can use the add method if necessary to put the custom add method in place. For instance, you might use a different API or have a complicated internal element structure.

Using a unique method to add components to a container, for instance.

@Tag("div")
public class MyComponentContainer extends Component {

    public void add(Component c) {
        getElement().appendChild(c.getElement());
    }
}
You can also try this code with Online Java Compiler
Run Code

Child components being attached to the DOM

A container component must attach the child to the DOM when a child component is introduced to the container component. The only prerequisite for a container component is this.

The child element is attached to the root element in the preceding illustration (as HasComponents does). If necessary, you can even utilize a more complicated element hierarchy or, alternatively, encapsulate each kid in its element.

An illustration would be to wrap an element around a child component.

@Tag("div")
public class MyComponentContainer extends Component {

    public void add(Component c) {
        Element childWrap = ElementFactory.createDiv();
        childWrap.appendChild(c.getElement());
        getElement().appendChild(childWrap);
    }
}
You can also try this code with Online Java Compiler
Run Code

Utilizing Methods for Component Hierarchy

GetChildren and getParent methods for component hierarchy, which are implemented based on the element hierarchy, automatically function for container components. These techniques also function when the child components are contained within wrapper elements.

A similar technique can be added to delete components.

Example

Detaching a component using the removeFromParent() function.

public void remove(Component c) {
    Element wrap = c.getElement().getParent();
    wrap.removeFromParent();
}
You can also try this code with Online Java Compiler
Run Code

Enabled and Disabled Container Components

All child components are automatically set as disabled when a container component is deactivated and updates from the client to the server are stopped.

The disabled status in the UI is accurately reflected in components that implement the HasEnabled interface. Setting the component's disabled property is the typical solution.

By modifying the onEnabledStateChanged() function, you can still visually update your container's elements or components to reflect the disabled status in the user interface even if they don't implement the HasEnabled interface.

For example, consider altering the onEnabledStateChanged() method to disable a component.

@Override
public void onEnabledStateChanged(boolean enabled) 
{
    super.onEnabledStateChanged(enabled);
    if (enabled) 
    {
        cElement.removeAttribute("disabled");
    } 
    else 
    {
        cElement.setAttribute("disabled", true);
    }
}
You can also try this code with Online Java Compiler
Run Code


To alter the element's visual aspect, you merely need to override the onEnabledStateChanged() method. Whether or not you override the method, communication between the client and server is stopped when the container is disabled.

When overriding, it's crucial to use super.onEnabledStateChanged(enabled). This is due to the shared logic to which every component associated with the enabled state must adhere.

Every time the enabled status changes, the onEnabledStateChanged() method is invoked. This holds true regardless of the status changes—direct setEnabled() calls, setEnabled() calls on parent containers, or attaching or releasing the component from a disabled container.

Frequently Asked Questions

What are the components of Vaadin?

Form inputs, visualization and interaction, layouts, and design system resources are components of Vaadin.

What is the relation between GWT and Vaadin?

The Vaadin framework is well-known to GWT programmers. Vaadin created a complete application framework using GWT. Along with the Errai framework, it is one of the main GWT-based frameworks and offers several intriguing features, including add-ons, themes, and connectors with other Java frameworks like Spring.

When was Vaadin discovered?

Vaadin Directory launched on March 30, 2010. The Vaadin Framework's main add-on components can now be distributed through a new channel for free or a fee. 95 add-ons were already available for download on the day of debut.

Why is Vaadin beneficial?

Vaadin is considerably more advantageous because it offers more components, layouts, and listeners than any traditional web technology. Vaadin is built on Java that's why it is fully object-oriented.

What distinguishes an element from a component?

Indeed, there is a distinction between elements and components. A component is a small portion of a more significant entity, typically a manufactured thing. An element, on the other hand, is one of the essential components that everything is made up of.

Conclusion

In this article, we have discussed the creation of components and the different ways to create the components. We have discussed creating components using single elements, using multiple elements, using existing components, and many other ways.

We hope this blog has helped you enhance your knowledge of Creating Components. If you want to learn more, check out our articles on All about VaadinRouter Exception HandlingVaadin Spring Scopes, and Basic Components Features.

Refer to our guided paths on Coding Ninjas Studio to learn more about DSA, Competitive Programming, JavaScript, System Design, etc. Enroll in our courses and refer to the mock test and problems available; look at the Top 150 Interview Puzzles interview experiences, and interview bundle for placement preparations.

Thank you

Do upvote our blog to help other ninjas grow. 

Happy Coding!

Live masterclass