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
Preview Feature

This is a preview version of Signals. You need to enable it with the feature flag com.vaadin.experimental.flowFullstackSignals. Preview versions may lack some planned features, and breaking changes may be introduced in any Vaadin version. We encourage you to try it out and provide feedback to help us improve it.

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)
// NumberSignal'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.value(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)
SharedValueSignal<String> label = new SharedValueSignal<>(String.class);
label.value("Close dialog");

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

label.value(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<?,?>>.
Source code
Element#bindProperty(String name, Signal<?> signal)
SharedValueSignal<Boolean> hidden = new SharedValueSignal<>(Boolean.class);
hidden.value(false);

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

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

// Bind the 'hidden' property to the signal
span.getElement().bindProperty("hidden", hidden);

// 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 synchronized with the bound signal
    Notification.show("'hidden' property changed to: " + event.getValue());
});

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

ClassList Binding

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

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

foo.value(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)
SharedValueSignal<String> color = new SharedValueSignal<>(String.class);
SharedValueSignal<String> background = new SharedValueSignal<>(String.class);
color.value("black");
background.value("white");

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

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

background.value(""); // 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.value(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.value(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.value(false);
// Button is now disabled

For component-level examples, see Binding Enabled State.

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.value("<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(WritableSignal<V> signal)

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

Source code
Java
SharedValueSignal<String> nameSignal = new SharedValueSignal<>(String.class);

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

// User types in field -> signal is updated
// 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.value(true);
// Field is now read-only

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 ""