> Markdown version of [Upgrading from Vaadin 25.2](https://vaadin.com/docs/next/upgrading/25-2-to-25-3). Section index: [llms.txt](https://vaadin.com/docs/next/upgrading/llms.txt)

# Upgrading from Vaadin 25.2 to 25.3

Vaadin 25.3 is a minor release, and for most applications the upgrade is a version bump. The system requirements are the same as for Vaadin 25.2: Java 21 or later, Spring Boot 4.1 or later, and Node.js 24 or later. This page lists the changes that can still need attention, followed by the deprecations to act on before Vaadin 26.

For what’s new in Vaadin 25.3, see the [release notes](https://github.com/vaadin/platform/releases/tag/25.3.0). If you’re upgrading from Vaadin 24, follow [Upgrading from Vaadin 24](https://vaadin.com/docs/next/upgrading.md) instead — it includes the Vaadin 25.3 changes.

## <a id="update-the-version"></a>Update the Version

Set the Vaadin version in the `pom.xml` or `gradle.properties` file:

**pom.xml**

```xml
<vaadin.version>25.3.0</vaadin.version>
```

**gradle.properties**

```properties
vaadinVersion=25.3.0
```

Use the latest 25.3 maintenance release, if one is available. See the [list of releases on GitHub](https://github.com/vaadin/platform/releases).

## <a id="build-and-frontend"></a>Build and Frontend

- Default `index.html`

  The build now generates the default `index.html` into `frontend/generated/`, and only when the project has no `frontend/index.html` of its own. An `index.html` that an older build generated into `frontend` — and that was committed to source control — takes precedence and hides later improvements to the default. If you haven’t customized it, delete it. See [Default Template & Entry Point](https://vaadin.com/docs/next/flow/advanced/modifying-the-bootstrap-page.md#default-bootstrap-template-and-entry-point).

- TypeScript 7 and React Router 8

  The frontend toolchain moves from TypeScript 6 to 7 and from React Router 7 to 8. The `tsconfig.json` that Vaadin generates is unchanged. If you have customized it, remove any compiler options that TypeScript 6 deprecated, as TypeScript 7 no longer accepts them. If your React views use React Router APIs directly, see the [React Router upgrade guide](https://reactrouter.com/upgrading/v7).

- Client-side engine

  The engine that runs in the browser is now written in TypeScript and bundled by Vite. It replaces the engine that Google Web Toolkit (GWT) compiled from Java. Applications need no changes. Only an add-on that compiled against `com.vaadin.client.*`, or a build step that referenced `VAADIN/static/client/`, is affected. See [Client-Side Engine Ported to TypeScript](https://vaadin.com/docs/next/upgrading.md#client-side-engine-ported-to-typescript).

## <a id="java-api-changes"></a>Java API Changes

- `Image`

  `Image` extends `HtmlComponent` instead of `HtmlContainer`, so it no longer has the `add()`, `remove()`, `removeAll()`, `setText()`, and `getText()` methods. An `img` element never rendered children or text. Remove those calls, and use `setAlt()` for the alternative text.

- Navigating to a location with a query string

  `UI.navigate(String)` parses a query string and fragment in the location, as in `ui.navigate("user/123?tab=orders")`. Passing a `QueryParameters` object together with such a location throws an `IllegalArgumentException`, since it would discard the parameters in the string. See [Navigating Between Routes](https://vaadin.com/docs/next/flow/routing/navigation.md).

- Custom servlets

  `VaadinServlet` no longer calls `serveStaticOrWebJarRequest()`, so overriding it has no effect. To customize how static resources are served, override `createStaticFileHandler()` instead.

- Spring configuration classes

  The `vaadin-spring` configuration classes are now Spring Boot auto-configurations, with `proxyBeanMethods=false`. This only affects code that extends or imports these classes, and relies on a call from one bean method to another returning the shared bean instance.

## <a id="security"></a>Security

When a log-in view is configured with `VaadinSecurityConfigurer.loginView()`, an unauthorized request for a sub-resource — a stylesheet, script, image, font, or web app manifest — is answered with `401 Unauthorized` instead of a redirect to the log-in view. A test or client that expects the redirect has to expect `401`. See [Security Changes in Vaadin 25.3](https://vaadin.com/docs/next/upgrading.md#security-changes-in-vaadin-25-3).

## <a id="components"></a>Components

- Grid: hidden columns

  Value providers, tooltip generators, and part name generators no longer run for hidden columns, and Grid sends no data to the browser for them. Showing a column generates its data again. Don’t rely on side effects of these callbacks, or on client-side access to the data of hidden columns.

- Grid: selection and item details

  Selection and item details react only to the user’s clicks. Selecting an item on the server no longer opens its details, and the selected row is no longer mirrored to the `activeItem` property of the web component. Update any client-side code that reads or sets `activeItem` to select a row or open its details.

- Dialog focus

  Non-modal dialogs still receive focus when opened, but no longer trap it: `Tab` moves on to the rest of the page. `setFocusTrap()` is deprecated — use `setAutofocus()` instead. See [Dialog](https://vaadin.com/docs/next/components/dialog.md).

- Multi-Select Combo Box

  The value is synchronized to the server on the web component’s `change` event. Client-side code that sets the `selectedItems` property directly has to dispatch a `change` event for the server to receive the new value. Server-side `setValue()` and user interaction aren’t affected.

## <a id="ai-integration-preview"></a>AI Integration (Preview)

The AI integration is still a preview feature, behind the `com.vaadin.experimental.aiComponents` feature flag, and Vaadin 25.3 changes its API:

- The `vaadin-ai-components-flow` artifact is replaced by two modules. The free `vaadin-ai-core-flow` module contains the orchestrator, the LLM providers, the component interfaces, and the `AIController` interface. The commercial `vaadin-ai-extensions-flow` module contains the built-in Grid, Chart, and Form controllers, which now require a commercial Vaadin subscription. The `vaadin-core` dependency includes only the free module, while `vaadin` includes both. Replace any explicit `vaadin-ai-components-flow` dependency. The Java package names are unchanged.

- `AIController.onRequest()` now takes a `RequestListener.RequestEvent`, and `onResponse(Throwable)` is now `onResponse(ResponseListener.ResponseEvent)`, where the error is available from `getError()`. Update custom controllers to the new signatures.

- `FormAIController` fires `addFieldValueChangeListener()` listeners once per changed field, replacing `addFieldValueChangedListener()`, which fired once per turn. `showFieldHighlight()` and `hideFieldHighlight()` are removed: fields that the AI changes are marked automatically with a marker that lets the user revert the change. Turn this off with `setFieldMarkerEnabled(false)`. Fields are also no longer set to read-only on the server while a turn runs.

See [AI Support](https://vaadin.com/docs/next/flow/ai-support.md) for details.

## <a id="observability-kit"></a>Observability Kit

Vaadin 25.3 comes with Observability Kit 5, a rewrite built on Micrometer. It isn’t a drop-in replacement for version 4: there’s no Java agent any more, and meter names, configuration, tracing data, and the custom instrumentation API have changed. If your application uses Observability Kit, follow [Migrating to Version 5](https://vaadin.com/docs/next/tools/observability/migrating-to-v5.md).

## <a id="browserless-testing-and-testbench"></a>Browserless Testing and TestBench

Some component testers now behave more like a browser, which can make existing tests fail:

- `NumberFieldTester`, `DatePickerTester`, `TimePickerTester`, and `DateTimePickerTester` accept a value that violates `min`, `max`, `step`, or a required constraint, and mark the field invalid, instead of throwing an `IllegalArgumentException`. Assert the validity instead of the exception.

- A read-only value component isn’t usable, so setting its value through a tester throws.

- Queries find the components set as a Grid column header, footer, or editor.

- `GridTester.getCellComponent()` returns the component that the grid rendered, and throws for a cell that the grid doesn’t render. Use `renderCellComponent()` for the old behavior.

- `test(treeGrid)` returns a `TreeGridTester`, and `test(gridContextMenu)` returns a `GridContextMenuTester`.

- A context menu has to be opened with `open()` before its items can be clicked or inspected.

- `CheckboxGroupTester.updateSelection()` is no longer public.

- Override `frameworkLookupServices()` instead of `lookupServices()` to replace a service that the Spring or Quarkus integration registers. `lookupServices()` is deprecated in favor of the [test configuration](https://vaadin.com/docs/next/flow/testing/browserless/test-configuration.md).

- In TestBench, `SelectElement.getSelectedText()` returns an empty string when no item is selected.

See [TestBench and Browserless Testing](https://vaadin.com/docs/next/upgrading.md#testbench-and-browserless-testing) for examples and details.

## <a id="deprecations-to-address-before-vaadin-26"></a>Deprecations to Address Before Vaadin 26

Deprecated APIs still work in Vaadin 25.3, but most of them are removed in Vaadin 26. Replacing them now makes the next upgrade easier.

| Deprecated                                                                                                                  | Replacement                                                                                                                                                                         |
| --------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `NativeTable` and the related `NativeTable*` components and TestBench elements                                              | The `Table` component family. See [Migrating from Native Table](https://vaadin.com/docs/next/components/html-elements/table.md#migrating-from-native-table).                        |
| `SessionLockListener`, `RpcInvocationListener`, and the `VaadinService` methods that add them                               | Events of the service event bus. See [Deprecated Listener Interfaces](https://vaadin.com/docs/next/flow/advanced/session-lock-and-rpc-listeners.md#deprecated-listener-interfaces). |
| `setItems(rootItems, childItemProvider)` and `setTreeData()` of Tree Grid, and the `TreeDataProvider(TreeData)` constructor | A `TreeDataProvider` with an explicit hierarchy format, as the default changes from `NESTED` to `FLATTENED` in Vaadin 26. See the example below.                                    |
| `ValueChangeMode.ON_BLUR`                                                                                                   | `ValueChangeMode.ON_CHANGE`, which fires on focus loss only when the value has changed.                                                                                             |
| `Dialog.setFocusTrap()`                                                                                                     | `Dialog.setAutofocus()`                                                                                                                                                             |
| `setRole()` of Dialog, Popover, and Badge                                                                                   | `setAriaRole()`                                                                                                                                                                     |
| `Tabs.indexOf()`                                                                                                            | `Tabs.getIndexOf()`                                                                                                                                                                 |
| `SplitLayout.setPrimaryStyle()` and `setSecondaryStyle()`                                                                   | Styling `getPrimaryComponent()` and `getSecondaryComponent()` directly.                                                                                                             |
| `LoginI18n.createDefault()` and `CrudI18n.createDefault()`                                                                  | A new instance with only the customized texts set. Unset texts fall back to the component defaults.                                                                                 |
| `ExtendedClientDetails.getCurrentDate()`                                                                                    | `ExtendedClientDetails.getBrowserTime()`                                                                                                                                            |
| `WebBrowser.isIPhone()`, `ExtendedClientDetails.isIPad()`, and `ExtendedClientDetails.isIOS()`                              | Feature detection, or `ExtendedClientDetails.getNavigatorPlatform()`.                                                                                                               |
| `VaadinServlet.serveStaticOrWebJarRequest()`                                                                                | Overriding `createStaticFileHandler()`.                                                                                                                                             |
| About 150 `VaadinIcon` constants, such as the `_O` outline variants and brand icons                                         | The replacement named in the Javadoc of each constant. For brand icons, use an icon set such as [Simple Icons](https://simpleicons.org).                                            |

To keep the current Tree Grid behavior, build the `TreeDataProvider` yourself instead of calling `setItems()`:

```java
// Before
treeGrid.setItems(rootFolders, Folder::children);

// After
TreeData<Folder> treeData = new TreeData<>();
treeData.addItems(rootFolders, Folder::children);
treeGrid.setDataProvider(new TreeDataProvider<>(treeData,
        HierarchicalDataProvider.HierarchyFormat.NESTED));
```

Use `HierarchyFormat.FLATTENED` instead to adopt the Vaadin 26 default now. It keeps the scroll position more reliably when the hierarchy changes, but it changes how some methods, such as `scrollToIndex()`, interpret their arguments. See [Hierarchy Formats](https://vaadin.com/docs/next/components/tree-grid/data-binding.md#hierarchy-formats).

These products and features are deprecated as well, and aren’t available in Vaadin 26:

- **Collaboration Kit** — migrate to signals. See [Migrating from Collaboration Kit to Signals](https://vaadin.com/docs/next/tools/collaboration/migrating-to-signals.md).

- **SSO Kit** — migrate to Spring Security. See [Migrating from SSO Kit to Spring Security](https://vaadin.com/docs/next/tools/sso/migrating-to-spring-security.md).

- **AppSec Kit** — a replacement service for Vaadin Enterprise is planned. See [AppSec Kit](https://vaadin.com/docs/next/tools/appsec.md).

- **Hilla Lit views and Vaadin Router** — migrate to React and React Router. See [Vaadin Router Deprecation](https://vaadin.com/docs/next/upgrading.md#vaadin-router-removal).
