> Markdown version of [Calling JavaScript](https://vaadin.com/docs/next/flow/component-internals/element-api/calling-javascript). Section index: [llms.txt](https://vaadin.com/docs/next/flow/llms.txt)

# Calling JavaScript from the Server

The Element API contains methods for executing JavaScript in the browser from the server side.

Declare the JavaScript in a Java interface and call it through `Element.executeJs(Class)`. The build collects the declared JavaScript into the frontend bundle, and the client runs it from there. Nothing is compiled from a string in the browser, so the call works under a content security policy that doesn’t allow `unsafe-eval`.

The other methods described on this page — `executeJs(String, Object…​)`, `callJsFunction()`, `JsFunction`, and `addJsInitializer()` — send the JavaScript to the browser as a string that’s compiled there. Avoid them for anything a declaration can express.

## <a id="declaring-javascript"></a>Declaring JavaScript in Java (V25.4 pre-release)

An interface annotated with `@JsDefinition` declares the JavaScript that its methods run, and the build collects that JavaScript into the bundle. Call the declared JavaScript through `Element.executeJs(Class)`, which hands out an implementation of the interface; calling a method of it schedules the JavaScript that the method declares.

Each method of the interface is annotated with `@JsExpression`, whose value is the JavaScript expression to run. The arguments of the call are available inside the expression as `$0`, `$1`, and so on, and the element the implementation was obtained from is `this`.

The arguments must be a type supported by the communication mechanism. The supported types are `String`, `Boolean`, `Integer`, `Double`, `JsonNode`, `Element`, `Component`, and `JsFunction`.

Passing a `JsFunction` is allowed, but it brings the browser-side compilation back, since the client builds such a function from its body string. Declare a method for the JavaScript instead of passing a function into it.

The last parameter of a method can be declared variadic, such as `String…​`, to accept a variable number of trailing arguments instead of a fixed one. The build turns it into a JavaScript rest parameter, so reference it the same way as any other parameter and spread it where the expression needs the individual values.

Example 1. Declaring and calling a variadic method

```java
@JsDefinition
public interface ClassNamesJs extends Serializable {

    @JsExpression("this.classList.add(...$0)")
    void add(String... classNames);
}
```

```java
public void highlight() {
    getElement().executeJs(ClassNamesJs.class)
            .add("selected", "highlighted");
}
```

Example 2. Declaring and calling JavaScript through a `@JsDefinition` interface

```java
@JsDefinition
public interface GreeterJs extends Serializable {

    @JsExpression("window.alert($0)")
    void showGreeting(String greeting);
}
```

```java
public void greet(String message) {
    getElement().executeJs(GreeterJs.class).showGreeting(message);
}
```

A method returns either `void` or `PendingJavaScriptResult`, to retrieve a return value the same way an expression does (see [Return Values](#return-values)).

Example 3. Declaring JavaScript that returns a value

```java
@JsDefinition
public interface OverflowJs extends Serializable {

    @JsExpression("return this.scrollWidth > this.clientWidth")
    PendingJavaScriptResult isContentClipped();
}
```

```java
public void updateTooltip() {
    getElement().executeJs(OverflowJs.class)
            .isContentClipped()
            .then(Boolean.class, this::setTooltipEnabled);
}
```

Nothing about the JavaScript is decided at the call site: the build generates one function per declared expression into the bundle, and the client runs that function after looking it up by an identifier of the JavaScript. The expression itself is never sent to the browser, and a production bundle carries the generated functions only — the Java names stay on the server.

> **Note:** The interface is checked when `executeJs(Class)` hands out the implementation. It must be annotated with `@JsDefinition`, and every method must be annotated with `@JsExpression` and return `void` or `PendingJavaScriptResult`. A `default` or `static` method is refused, since it’s implemented in Java rather than declaring JavaScript to run in the browser.

When the JavaScript isn’t about a particular element, declare it the same way and run it through `Page.executeJs(Class)`, which works with global browser APIs instead of with an element (see [Accessing the Browser Page](https://vaadin.com/docs/next/flow/advanced/browser-access.md#declaring-javascript-in-java)).

## <a id="return-values"></a>Return Values

Add a listener to the `PendingJavaScriptResult` instance that a call answers with to access the value from a `return` statement in the JavaScript. This works the same way for a declared expression, an [`executeJs()` expression](#execute-js), and a function called through [`callJsFunction()`](#call-js-function). A declared method has to declare `PendingJavaScriptResult` as its return type to give access to the result.

Example 4. Checking for support of Constructable Stylesheets in the browser

```java
@JsDefinition
public interface FeatureDetectionJs extends Serializable {

    @JsExpression("return 'adoptedStyleSheets' in document")
    PendingJavaScriptResult supportsConstructableStylesheets();
}
```

```java
public void checkConstructableStylesheets() {
    getElement().executeJs(FeatureDetectionJs.class)
            .supportsConstructableStylesheets()
            .then(Boolean.class, supported -> {
                if (supported) {
                    System.out.println(
                            "Feature is supported");
                } else {
                    System.out.println(
                            "Feature isn't supported");
                }
            });
}
```

If the return value is a JavaScript `Promise`, the client only sends the return value to the server when the `Promise` is resolved.

### <a id="deserializing-generic-types-with-typereference"></a>Deserializing Generic Types with TypeReference

The `then()` method accepts a `Class` parameter for simple types, but this doesn’t work for generic types like `List<Person>` due to Java type erasure. For these cases, use the Jackson `TypeReference` overloads.

Example 5. Deserializing a JavaScript array into a `List<Person>`

```java
@JsDefinition
public interface ItemsJs extends Serializable {

    @JsExpression("return this.getItems()")
    PendingJavaScriptResult getItems();

    @JsExpression("return this.getPersonMap()")
    PendingJavaScriptResult getPersonMap();
}
```

```java
getElement().executeJs(ItemsJs.class).getItems()
        .then(new TypeReference<List<Person>>() {},
                items -> {
                    // items is List<Person>
                    items.forEach(person ->
                            System.out.println(person.getName()));
                });
```

An error handler can be provided as a second callback. The handler receives the error message from the failed JavaScript execution as a `String`:

```java
getElement().executeJs(ItemsJs.class).getItems()
        .then(new TypeReference<List<Person>>() {},
                items -> processItems(items),
                errorMessage -> handleError(errorMessage));
```

You can also use `toCompletableFuture(TypeReference)` to get the result as a `CompletableFuture`:

```java
CompletableFuture<Map<String, Person>> future = getElement()
        .executeJs(ItemsJs.class).getPersonMap()
        .toCompletableFuture(
                new TypeReference<Map<String, Person>>() {});
```

## <a id="execute-js"></a>`executeJs` Method

The `Element.executeJs()` method runs a JavaScript expression given as a string. The browser compiles the expression, which a content security policy that doesn’t allow `unsafe-eval` blocks. Declare the JavaScript in Java instead (see [Declaring JavaScript in Java](#declaring-javascript)). Use this method only for JavaScript that can’t be declared — an expression that isn’t known until runtime, for example.

The `executeJs()` method accepts two parameters: the JavaScript expression to invoke; and the parameters to pass to the expression. The given parameters are available as variables named `$0`, `$1`, and so on.

The arguments passed to the expression must be a type supported by the communication mechanism. The supported types are `String`, `Integer`, `Double`, `Boolean`, `JsonNode`, `Element`, `Component`, and `JsFunction` (see [Passing JavaScript Functions](#js-function)).

Example 6. Calling `MyModule.complete(true)` on the client side

```java
public void complete() {
    getElement().executeJs("MyModule.complete($0)", true);
}
```

Example 7. Passing a JSON array to a JavaScript expression

```java
public void setItems(List<String> items) {
    getElement().executeJs("this.items = $0", items);
}
```

> **Warning: Avoid Script Injection Vulnerabilities**
>
> Always pass arguments using the `$0`, `$1`, …​ notation to avoid script injection vulnerabilities. Never concatenate or interpolate strings to build JavaScript code to be executed.

If you need to run JavaScript without having access to an element, use the `UI.getCurrentOrThrow().getPage().executeJs()` method.

## <a id="call-js-function"></a>`callJsFunction` Method

The `Element.callJsFunction()` method allows you to run a client-side component function from the server side. The method accepts two parameters: the name of the function to call; and the arguments to pass to the function.

The call is sent to the browser as an expression and compiled there, the same way `executeJs()` is, so it also needs a content security policy that allows `unsafe-eval`. A definition method that declares an expression such as `return this.clearSelection()` calls the same client-side function without one (see [Declaring JavaScript in Java](#declaring-javascript)).

The arguments passed to the function must be a type supported by the communication mechanism. The supported types are `String`, `Boolean`, `Integer`, `Double`, `JsonNode`, `Element`, `Component`, and `JsFunction` (see [Passing JavaScript Functions](#js-function)).

Example 8. Calling the `clearSelection()` JavaScript function on the root element from the server side

```java
public void clearSelection() {
    getElement().callJsFunction("clearSelection");
}
```

Example 9. Calling the `expand(otherComponentElement)` JavaScript function on the root element from the server side

```java
public void setExpanded(Component otherComponent) {
    getElement().callJsFunction("expand",
            otherComponent.getElement());
}
```

Example 10. Passing a JSON object to a JavaScript function

```java
public void configure(String label, int count) {
    ObjectNode config = JacksonUtils.createObjectNode();
    config.put("label", label);
    config.put("count", count);
    config.put("enabled", true);
    getElement().callJsFunction("configure", config);
}
```

## <a id="undelivered-invocations"></a>Undelivered Invocations (since V25.3)

An invocation scheduled on the server is held in memory until it’s written into a response for the browser. An application that keeps scheduling invocations which never reach the browser grows until it runs out of memory. Once 1000 invocations for one UI are waiting to be sent, Flow logs a warning naming the component they belong to, the expression of the most recent one, and why nothing is being delivered. The warning is logged once per UI.

Invocations pile up whenever nothing carries them to the browser:

- **The owner is detached.** An invocation for a detached element is held until that element is attached again, which never happens for a component the application has discarded.

- **The owner is invisible.** Invocations for an invisible component are kept until it becomes visible.

- **The UI has no open push connection.** Nothing is sent until the browser makes a request of its own, which a closed tab whose session hasn’t expired yet never does.

Where only the latest value matters — a progress value, a clock, a live measurement — avoid scheduling a new invocation for every update:

- Keep the `PendingJavaScriptResult` that `executeJs()` returns, and call `cancelExecution()` on it before scheduling the next one.

- If the invocation only sets an element property, use `Element.setProperty()` instead of `executeJs()`. Only the last value of a property is sent.

- In a background task, compare `UI.getLastUpdateSentTimestamp()` against the current time and stop scheduling updates while the browser isn’t receiving them.

The timestamp is readable without the session lock, so a background task can decide whether to update the UI before acquiring it:

```java
if (Duration.between(ui.getLastUpdateSentTimestamp(), Instant.now())
        .compareTo(STALE_THRESHOLD) < 0) {
    ui.access(() -> statusLabel.setText(statusText));
}
```

It tells when the pending updates were last written towards the browser, not that the browser received them, and for a UI that has had no response written yet it’s the time the UI was created.

To find the code that schedules the invocations, enable debug logging for `com.vaadin.flow.component.internal.PendingJavaScriptInvocationUtil`, which then also logs the call site of the invocation that triggered the warning. Turning that logger off silences the warning.

## <a id="js-function"></a>Passing JavaScript Functions (since V25.2)

A `JsFunction` lets you build a reusable JavaScript function on the server and pass it as a parameter to `executeJs()` or `callJsFunction()`. The function arrives on the client as a real callable function with its captured values pre-bound, so you don’t need to concatenate JavaScript fragments to embed server-side values.

The function body is compiled on the client, so it needs a content security policy that allows `unsafe-eval` — also when the function is passed to a method of a JavaScript definition. Where the body is known in advance, declare the JavaScript in Java instead (see [Declaring JavaScript in Java](#declaring-javascript)).

The first argument to `JsFunction.of()` is a JavaScript function body. The remaining arguments are captured values, referenced inside the body as `$0`, `$1`, … using the same naming convention as `executeJs()` parameters.

Example 11. Defining a function and invoking it

```java
JsFunction greet = JsFunction.of(
        "return $0 + ' ' + $1;", "Hello", "World");
getElement().executeJs(
        "this.textContent = $0();", greet);
```

Captures may be any value supported as an `executeJs()` parameter. An attached `Element` arrives as the corresponding DOM node; a detached `Element` arrives as `null`.

Example 12. Capturing an element

```java
Div target = new Div();
add(target);

JsFunction mutate = JsFunction.of(
        "$0.textContent = 'updated';",
        target.getElement());
getElement().executeJs("$0();", mutate);
```

### <a id="declaring-runtime-arguments"></a>Declaring Runtime Arguments

Use `withArguments()` to declare named parameters that the function accepts at call time. The body references them by name, and the JavaScript that invokes the function passes them positionally:

Example 13. A function with runtime arguments

```java
JsFunction format = JsFunction
        .of("return prefix + ':' + suffix;")
        .withArguments("prefix", "suffix");
getElement().executeJs(
        "this.textContent = $0('alpha', 'beta');", format);
```

### <a id="controlling-this"></a>Controlling `this`

In JavaScript, the value of `this` inside a function depends on how the function is invoked, not where it is defined. The body of a `JsFunction` follows this convention – `this` is not bound to the host element automatically.

When the function is invoked as `$0(…​)` from inside an `executeJs()` expression, the body’s `this` is the global object (or `undefined` in strict mode), not the element on which `executeJs()` was called. To set `this` explicitly, invoke the function with `Function.prototype.call()`: its first argument becomes `this` inside the body.

Example 14. Calling the function with a specific `this`

```java
JsFunction setOwnText = JsFunction
        .of("this.textContent = msg;")
        .withArguments("msg");
getElement().executeJs(
        "$0.call(this, 'host element text');", setOwnText);
```

If the body always needs to reference the same element regardless of how the function is called, pass it as a capture instead of relying on `this`.

## <a id="add-js-initializer"></a>Client-Side Lifecycle With `addJsInitializer` (since V25.2)

The `Element.addJsInitializer()` method registers a JavaScript expression that runs each time a client-side DOM node is created for the element, and whose returned cleanup callback runs when that DOM node is discarded or the returned `Registration` is removed.

Use this when you need to install something on the client-side DOM – an event listener, a third-party widget, an observer – and reliably tear it down. A one-shot `executeJs()` call doesn’t cover two cases: a real re-attach gives the element a brand-new DOM node that no longer has your listener, and cleanup from a server-side detach listener cannot be delivered because the element is leaving the tree.

The expression is compiled in the browser, so `addJsInitializer()` needs a content security policy that allows `unsafe-eval`. No declaration-based counterpart exists; under a stricter policy, install and tear down from a client-side module of your own instead.

The expression syntax is the same as `executeJs()`: `this` is the host element on the client, and parameters are referenced as `$0`, `$1`, …. If the expression returns a function, that function is invoked at teardown.

Example 15. Installing a listener with cleanup

```java
Registration registration = getElement().addJsInitializer("""
        const handler = (event) => console.log($1, event.target);
        this.addEventListener($0, handler);
        return () => this.removeEventListener($0, handler);
        """, "click", "clicked");
```

Here `$0` is `"click"` and `$1` is `"clicked"`, so the event type and the log label come from the server rather than being hard-coded in the expression.

Remove the registration on the server when the listener is no longer needed; the cleanup callback then runs on the client.

### <a id="re-attach-semantics"></a>Re-Attach Semantics

The initializer is re-run after a real re-attach – when the element is removed from the DOM in one round trip and re-added in a later one, and so the browser receives a fresh DOM node. It is **not** re-run when the element is detached and re-attached on the server inside a single round trip, because the client never discarded its DOM.

### <a id="cleanup-constraints"></a>Cleanup Constraints

The return value of the expression is read synchronously. A function is treated as the cleanup callback; returning `null`, `undefined`, or nothing at all (no `return`) means there’s no cleanup. Returning any other value – including a `Promise` resolving to a function – is logged as an error on the client.

If setup is asynchronous, don’t return the `Promise`. Keep a reference to the pending work and return a cleanup function that awaits it before tearing down. Awaiting the same promise in the cleanup callback ensures the resource is torn down even if cleanup runs before the asynchronous setup has finished – otherwise a slow import could create the widget after cleanup has already run, leaking it:

```java
getElement().addJsInitializer("""
        const widgetPromise = import('./my-widget.js')
                .then((module) => module.create(this));
        return async () => (await widgetPromise).destroy();
        """);
```

`AB7EDF45-DB22-4560-AF27-FF1DC6944482`
