Docs

Documentation versions (currently viewingVaadin 25.1 (pre-release))

Element Bindings

Binding signals to Element properties, attributes, and styles for advanced use cases.

This section covers low-level Element bindings for direct DOM manipulation. These APIs are useful when building custom components or when you need fine-grained control over element attributes and properties.

Note

For most applications, use the component-level binding methods covered in Component Bindings. Component methods like bindText(), bindVisible(), and bindEnabled() provide a simpler API for common use cases. Use Element bindings when:

  • Building custom components

  • Working with HTML attributes not exposed by component APIs

  • Binding element properties for JavaScript interoperability

Binding Rules

All element bindings follow consistent rules:

  • When a feature is bound to a signal, its value is kept synchronized with the signal value while the element is in the attached state

  • When the element is detached, signal value changes have no effect

  • Passing null as the signal unbinds the existing binding

  • While a signal is bound, any attempt to set the value manually (other than through the signal) throws BindingActiveException

  • Attempting to bind a new signal while one is already bound throws BindingActiveException

Text Binding

Source code
Element#bindText(Signal<String> signal)
// SharedNumberSignal's Double type must be mapped to String
Signal<String> signal = counter.map(value -> String.format("Clicked %.0f times", value));

span.getElement().bindText(signal);
// span's text content is now "Clicked 0 times"
Source code
Binding lifecycle
span.getElement().getText(); // returns "Clicked 0 times"
span.getElement().setText(""); // throws BindingActiveException

span.getElement().removeFromParent(); // detaching from the UI
span.getElement().getText(); // returns "Clicked 0 times"
span.getElement().setText(""); // throws BindingActiveException
counter.set(5); // updating the signal value
span.getElement().getText(); // returns "Clicked 0 times"
add(span); // re-attaching the element to the UI
span.getElement().getText(); // returns "Clicked 5 times"

span.getElement().bindText(null); // unbinds the existing binding
span.getElement().getText(); // returns "Clicked 5 times"
span.getElement().setText("");
span.getElement().getText(); // returns ""

Attribute Binding

Source code
Element#bindAttribute(String attribute, Signal<String> signal)
ValueSignal<String> label = new ValueSignal<>("Close dialog");

button.getElement().bindAttribute("aria-label", label);
// DOM has "<button aria-label="Close dialog">"

label.set(null);
// DOM has "<button>" (attribute removed)

Property Binding

Property binding supports various value types: String, Boolean, Double, BaseJsonNode, Object (bean), List and Map.

Note
Typed Lists and Maps are not supported. The signal must be of type Signal<List<?>> or Signal<Map<?,?>>.
Element#bindProperty(String name, Signal<T> signal, SerializableConsumer<T> writeCallback)

The third parameter is a write callback that propagates client-side property changes back to the signal. Pass null for read-only bindings where changes only flow from signal to element.

Source code
Java
ValueSignal<Boolean> hidden = new ValueSignal<>(false);

span.getElement().bindProperty("hidden", hidden, null);
hidden.set(!hidden.peek()); // toggles 'hidden' property
Source code
String type
ValueSignal<String> title = new ValueSignal<>("Hello");
span.getElement().bindProperty("title", title, null);
title.set("World"); // updates 'title' property
Source code
Double type
SharedNumberSignal width = new SharedNumberSignal();
width.set(100.5);
span.getElement().bindProperty("width", width, null);
width.incrementBy(50); // updates 'width' property to 150.5
Source code
Object (bean) type
record Person(String name, int age) {}

ValueSignal<Person> person = new ValueSignal<>(new Person("John", 30));
span.getElement().bindProperty("person", person, null);
person.set(new Person("Jane", 25));
// element.person is now {name: 'Jane', age: 25}
Source code
List type
ValueSignal<List<String>> items = new ValueSignal<>(List.of("Item 1", "Item 2"));
span.getElement().bindProperty("items", items, null);
items.set(List.of("Item A", "Item B", "Item C"));
// element.items is now ['Item A', 'Item B', 'Item C']
Source code
Map type
ValueSignal<Map<String, String>> config = new ValueSignal<>(Map.of("key1", "value1"));
span.getElement().bindProperty("config", config, null);
config.set(Map.of("key1", "value1", "key2", "value2"));
// element.config is now {key1: 'value1', key2: 'value2'}
Source code
Two-way binding with property change listener
ValueSignal<Boolean> hidden = new ValueSignal<>(false);

// Bind the 'hidden' property to the signal with a write callback for two-way sync
span.getElement().bindProperty("hidden", hidden, hidden::set);

// Add a property change listener that synchronizes on 'change' DOM event
span.getElement().addPropertyChangeListener("hidden", "change", event -> {
    // When the property changes on the client (via DOM event),
    // the changed value is propagated back to the signal via the write callback
    Notification.show("'hidden' property changed to: " + event.getValue());
});

// After a property change event from the client, signal.get() returns the updated value

Flashing a CSS Class

Element#flashClass(String className)

Use flashClass() to temporarily add a CSS class that triggers a CSS animation, then automatically removes it when the animation ends. This is useful for visual feedback like highlighting a value that changed:

Source code
Java
element.flashClass("highlight");

The method removes the class (if present), forces a DOM reflow, and re-adds it to restart the animation. An animationend listener removes the class when the animation completes. If no CSS animation is defined for the class, it is removed immediately.

Define the animation in CSS:

Source code
CSS
.highlight {
    animation: flash 0.5s ease-out;
}
@keyframes flash {
    from { background-color: yellow; }
    to { background-color: transparent; }
}

You can combine flashClass() with signal effects to flash whenever a value changes:

Source code
Java
SharedNumberSignal counter = new SharedNumberSignal();

Span counterSpan = new Span();
counterSpan.bindText(counter.map(c -> String.format("Count: %.0f", c)));

Signal.effect(counterSpan, () -> {
    counter.get(); // Track the counter signal
    counterSpan.getElement().flashClass("highlight");
});

ClassList Binding

Source code
ClassList#bind(String name, Signal<Boolean> signal)
ValueSignal<Boolean> foo = new ValueSignal<>(false);
ValueSignal<Boolean> bar = new ValueSignal<>(true);

span.getElement().getClassList().bind("foo", foo);
span.getElement().getClassList().bind("bar", bar);
// DOM has "<span class='bar'>"

foo.set(true);
// DOM has "<span class='bar foo'>"

span.getElement().getClassList().clear();
// DOM has "<span class>". Binding is also removed.

Style Binding

Source code
Style#bind(String name, Signal<String> signal)
ValueSignal<String> color = new ValueSignal<>("black");
ValueSignal<String> background = new ValueSignal<>("white");

span.getElement().getStyle().bind("color", color);
span.getElement().getStyle().bind("background", background);
// DOM has "<span style='color: black; background: white'>"

color.set("red");
background.set("gray");
// DOM has "<span style='color: red; background: gray'>"

background.set(""); // same with null
// DOM has "<span style='color: red;'>"

span.getElement().getStyle().clear();
// DOM has "<span style>". Binding is also removed.

ThemeList Binding

Source code
ThemeList#bind(String name, Signal<Boolean> signal)
ValueSignal<Boolean> darkMode = new ValueSignal<>(false);

component.getThemeList().bind("dark", darkMode);
// Theme "dark" is applied when darkMode is true

darkMode.set(true);
// Component now has "dark" theme applied

For component-level theme binding examples, see Binding Theme Variants.

Visibility Binding

Components provide bindVisible() directly. The Element-level binding follows the same pattern:

Source code
Element#bindVisible(Signal<Boolean> signal)
ValueSignal<Boolean> visible = new ValueSignal<>(true);

element.bindVisible(visible);
// Element is visible when visible is true

visible.set(false);
// Element is now hidden

For component-level examples, see Binding Visibility.

Enabled Binding

Components provide bindEnabled() directly. The Element-level binding:

Source code
Element#bindEnabled(Signal<Boolean> signal)
ValueSignal<Boolean> enabled = new ValueSignal<>(true);

button.getElement().bindEnabled(enabled);
// Button is enabled when enabled is true

enabled.set(false);
// Button is now disabled

For component-level examples, see Binding Enabled State.

Change Callbacks

All binding methods return a SignalBinding that supports change callbacks via onChange():

Source code
Java
span.bindText(priceSignal.map(p -> "$" + p))
    .onChange(ctx -> {
        if (ctx.isBackgroundChange()) {
            ctx.getElement().flashClass("highlight");
        }
    });

The BindingContext provides:

  • getOldValue() / getNewValue() — the previous and current bound values

  • getElement() — the target element

  • getComponent() — the owning component (if any)

  • isInitialRun() — whether this is the first execution

  • isBackgroundChange() — whether triggered by another session or background thread

HTML Content Binding

Source code
Html#bindHtmlContent(Signal<String> signal)
ValueSignal<String> htmlContent = new ValueSignal<>("<strong>Bold text</strong>");

Html html = new Html("<span></span>");
html.bindHtmlContent(htmlContent);
// HTML content is now "<strong>Bold text</strong>"

htmlContent.set("<em>Italic text</em>");
// HTML content is now "<em>Italic text</em>"
Warning
Be careful with HTML content binding to avoid XSS vulnerabilities. Never bind user-provided content directly without proper sanitization.

Form Field Bindings

Form field bindings provide two-way synchronization between fields and signals. For comprehensive examples including all supported field types, see Two-Way Form Field Binding in Component Bindings.

Two-Way Value Binding

HasValue#bindValue(Signal<V> signal, SerializableConsumer<V> setter)

The bindValue() method creates a two-way binding between a form field and a signal:

Source code
Java
ValueSignal<String> nameSignal = new ValueSignal<>("");

TextField nameField = new TextField("Name");
nameField.bindValue(nameSignal, nameSignal::set);

// User types in field -> signal is updated via setter
// Signal changes -> field is updated

Read-Only Binding

HasValue#bindReadOnly(Signal<Boolean> signal)

Binds the read-only state of a form field to a boolean signal:

Source code
Java
ValueSignal<Boolean> readOnly = new ValueSignal<>(false);

TextField field = new TextField();
field.bindReadOnly(readOnly);

readOnly.set(true);
// Field is now read-only

Required Indicator Binding

HasValue#bindRequiredIndicatorVisible(Signal<Boolean> signal)

Binds the required indicator visibility of a form field to a boolean signal:

Source code
Java
ValueSignal<Boolean> required = new ValueSignal<>(true);

TextField field = new TextField("Name");
field.bindRequiredIndicatorVisible(required);

SignalPropertySupport Helper

Not all component features delegate directly to the state in Element. For those features, the SignalPropertySupport helper class ensures that state management behaves consistently with other element bindings.

Source code
Java
class MyComponent extends Div {
    private final SignalPropertySupport<String> textProperty =
            SignalPropertySupport.create(this, value -> {
                getElement().executeJs("this.textContent = 'Content: ' + $0", value);
            });

    public String getTextContent() {
        return textProperty.get();
    }

    public void setTextContent(String text) {
        textProperty.set(text);
    }

    public void bindTextContent(Signal<String> textSignal) {
        textProperty.bind(textSignal);
    }
}

Usage:

Source code
Java
MyComponent component = new MyComponent();
component.bindTextContent(counter.map(v -> "Signal value: " + v));
add(component);
// textContent in browser is "Content: Signal value: 0.0"

component.getTextContent(); // returns "Signal value: 0.0"
component.setTextContent(""); // throws BindingActiveException

component.bindTextContent(null); // unbinds the existing binding
component.setTextContent("");
component.getTextContent(); // returns ""