Vaadin Component Basics
All Vaadin components consist of a client-side HTML element and a server-side Java component. The server-side components extend the com.vaadin.flow.component.Component base class. Vaadin provides support for keeping the client-side element and server-side component in sync.
Defining a Root Element
Every component is associated with a root Element, which is accessible from the Component.getElement() method. The @Tag annotation specifies the HTML tag name of the root element.
You use the Element API to interact with the client-side elements, for example by manipulating attributes, properties and styles, and reacting to events. See the Element API reference guide for more information.
TextField component based on an <input> elementSource code
TextField.java
You can use predefined constants in the @Tag annotation. For example, the @Tag("input") annotation is equivalent to @Tag(Tag.INPUT). Most tag names have a constant, but not all.
Using Multiple Elements
A component can consist of multiple elements in the DOM tree. In this case, the root element is still defined using the @Tag annotation, and other elements are created and appended to the root element using the Element API.
LabeledTextField component with <input> and <label> elements inside a <div> root elementSource code
LabeledTextField.java
package com.vaadin.demo.reference.componentinternals.basics;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.dom.Element;
@Tag("div")
public class LabeledTextField extends Component {
private final Element labelElement = new Element("label");
private final Element inputElement = new Element("input");
public LabeledTextField() {
getElement().appendChild(labelElement, inputElement);
}
}LabeledTextField.java
This generates the following DOM-tree structure in the browser:
Source code
HTML
<div>
<label></label>
<input>
</div>Extending a Component
If you extend an existing component, the root element is inherited from the parent component class. You can still use the Element API to manipulate the root element or create and append child elements. However, you don’t need to use the @Tag annotation in this case.
LabeledTextField component created aboveSource code
CustomTextField.java
package com.vaadin.demo.reference.componentinternals.basics;
import com.vaadin.flow.dom.Element;
public class CustomTextField extends LabeledTextField {
private final Element errorElement = new Element("span");
public CustomTextField() {
super();
getElement().appendChild(errorElement);
}
}CustomTextField.java
This generates the following DOM-tree structure in the browser:
Source code
HTML
<div>
<label></label>
<input>
<span></span>
</div>Composite Components
When you create a new component by combining existing components, you should extend the Composite<T> class, where T is the type of the root component. This does not affect the DOM structure, but prevents users of your component from accessing the API of the root component directly.
CompositeTextField component with Input and NativeLabel components inside a Div root componentSource code
CompositeTextField.java
package com.vaadin.demo.reference.componentinternals.basics;
import com.vaadin.flow.component.Composite;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.Input;
import com.vaadin.flow.component.html.NativeLabel;
public class CompositeTextField extends Composite<Div> {
private final NativeLabel label;
private final Input input;
public CompositeTextField(String labelText, String value) {
label = new NativeLabel();
label.setText(labelText);
input = new Input();
input.setValue(value);
// Users of CompositeTextField can't access the div directly since
// getContent() is protected.
var div = getContent();
div.add(label, input);
}
// Declare public API here.
}CompositeTextField.java
This generates the following DOM-tree structure in the browser:
Source code
HTML
<div>
<label></label>
<input>
</div>Creating a Java API
The Element API provides low-level access to the client-side element. You typically want to create a higher-level Java API that hides these details from the users of your component.
A Vaadin component API consists of:
-
Properties for accessing and setting values. This is covered in the Component Properties reference guide.
-
Events and event listeners for reacting to user actions. This is covered in the Declaring and Firing Component Events reference guide.
-
Other methods that act on the component. Some of them may use the Element API to call JavaScript functions on the client side. This is covered in the Remote Procedure Calls reference guide.
value property, and reacting to value changesSource code
TextField.java
Lifecycle Callbacks
The topmost component in any component hierarchy is the UI instance. The UI may represent an entire browser window (or tab), or some part of an HTML page where a Vaadin application is embedded.
Attach to UI
Whenever a component is added to a UI, either directly or indirectly through another component, it is considered to be attached to the UI. When a component is removed from the UI, it is considered to be detached from the UI.
The Component class provides an onAttach() method that is called when the component has been attached to a UI. Override this method to perform initialization that requires the component to be attached. The default implementation is empty, so you don’t need to call super.onAttach() unless you are extending another component class that requires it.
onAttach() methodSource code
UserNameLabel.java
package com.vaadin.demo.reference.componentinternals.basics;
import com.vaadin.flow.component.AttachEvent;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.Tag;
@Tag("div")
public class UserNameLabel extends Component {
@Override
protected void onAttach(AttachEvent attachEvent) {
// This assumes the username has been stored in the session after login
String userName = (String) attachEvent.getSession().getAttribute("username");
getElement().setText("Hello %s, weclome back!".formatted(userName));
}
}UserNameLabel.java
You can also use the Component.addAttachListener() method to register an attach listener instead of overriding the onAttach() method. The listener is invoked after the onAttach() method. This is useful when you want to add attach behavior to an existing component without creating a subclass.
Detach from UI
The Component class also provides a onDetach() method that is called right before the component is detached from the UI. Override this method to perform cleanup, for example to release resources that were acquired in the onAttach() method. The default implementation is empty, so you don’t need to call super.onDetach() unless you are extending another component class that requires it.
onAttach() method and unsubscribing in the onDetach() methodSource code
ShoppingCartSummaryLabel.java
package com.vaadin.demo.reference.componentinternals.basics;
import java.util.EventObject;
import java.util.function.Consumer;
import com.vaadin.flow.component.AttachEvent;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.DetachEvent;
import com.vaadin.flow.component.Tag;
@Tag("div")
public class ShoppingCartSummaryLabel extends Component {
private final Consumer<EventObject> eventHandler = this::onCartSummaryUpdate;
@Override
protected void onAttach(AttachEvent attachEvent) {
// This assumes the session already contains a ShopEventBus
var eventBus = attachEvent.getSession().getAttribute(ShopEventBus.class);
eventBus.register(eventHandler);
}
@Override
protected void onDetach(DetachEvent detachEvent) {
var eventBus = detachEvent.getSession().getAttribute(ShopEventBus.class);
eventBus.unregister(eventHandler);
}
private void onCartSummaryUpdate(EventObject event) {
// update cart summary ...
}
}
interface ShopEventBus {
void register(Consumer<EventObject> eventHandler);
void unregister(Consumer<EventObject> eventHandler);
}ShoppingCartSummaryLabel.java
You can also use the Component.addDetachListener() method to register a detach listener instead of overriding the onDetach() method. The listener is invoked after the onDetach() method. This is useful when you want to add detach behavior to an existing component without creating a subclass.
Setting Id
You can set an Id for any component. The Id is passed to the client side as the id of the corresponding element. However, an Id must be unique within the page, as it can be used to select the element in JavaScript code or CSS rules.
IdSource code
SetIdView.java
2E20FB94-B5FD-4105-B53B-3EECA329EFF3