github vaadin/flow 25.2.0
Vaadin Flow 25.2.0

6 hours ago

Vaadin Flow 25.2 brings server-side Java APIs for a broad set of browser capabilities — Geolocation, Clipboard (copy and paste), Fullscreen, Screen Wake Lock, Screen Orientation, Web Share, and Page Visibility — together with a new client-side action/trigger framework for wiring browser behavior to server logic without hand-written JavaScript. The reactive Signals API gains router and page-visibility signals, routing adds stateless route hierarchies and dynamic page titles, and the release hardens security defaults (X-Frame-Options, URL-scheme validation, npm supply-chain delay). It also ships major tooling upgrades: Vite 8 (Rolldown), Spring Boot 4.1, TypeScript 6, and JUnit Jupiter 6.1.

Breaking Changes

  • Stop auto-running vaadinPrepareFrontend in development mode (Gradle)
    Pull request · Issue

    IDE-triggered Gradle builds no longer run vaadinPrepareFrontend via processResources, which previously interfered with the running Vite dev server and broke hot deploy. Since Vaadin 25 the dev server prepares the frontend at runtime. Restore the old behavior with alwaysExecutePrepareFrontend = true.

  • Auto-apply context:// for @StyleSheet values
    Pull request

    Bare relative @StyleSheet hrefs now resolve against the context root instead of <base>, fixing 404s when vaadin.urlMapping is set to a non-root path. http(s)://, //, context://, base://, and /-prefixed values pass through unchanged; path traversals are rejected.

  • NativeLabel.setFor() lazily resolves and auto-generates IDs
    Pull request

    setFor(Component) now resolves the target's ID lazily at sync time, auto-generating one if missing, so developers no longer need to assign IDs manually.

  • Secure-by-default behavior changes — see Security: X-Frame-Options is now sent as SAMEORIGIN by default, and Anchor/IFrame/Page#open reject script-capable URL schemes (javascript:, data:) unless the unsafe variants are used.

New Features

Browser API Wrappers

  • Geolocation API
    Pull request

    A new Geolocation utility wraps the browser Geolocation API: one-shot reads via getPosition(onSuccess, onError) and continuous tracking via watchPosition(...), all asynchronous and delivered on the UI thread. Results use sealed types (GeolocationPosition | GeolocationError, plus GeolocationPending for the watcher signal) for exhaustive pattern matching. Watches auto-stop on detach; stop()/resume() are explicit. A GeolocationClientFactory Lookup SPI lets external/browserless test drivers swap the client.
    Follow-ups: #24270, #24268, #24211, #24259, #24279

    Button locate = new Button("Use my location");
    locate.addClickListener(e -> Geolocation.getPosition(
            pos -> showNearest(pos.coords().latitude(), pos.coords().longitude()),
            err -> showManualEntry()));
  • Clipboard API (write, read, and paste)
    #23615 · #24551 · #24552 · #24570 · #24583

    A Clipboard entry point binds clipboard access to a user gesture. Clipboard.onClick(component) produces a ClipboardBinding for writing plain text, HTML, field values, image/png, and multi-format ClipboardContent, with fire-and-forget and observed (onCopied/onError) variants — plus a matching read/readText/readHtml side. Clipboard.onPaste(...) forwards native paste events to a server-side listener, and Clipboard.onFilePaste(...) streams pasted files through an UploadHandler.

    Button copy = new Button("Copy");
    Clipboard.onClick(copy).writeText(textField,
            copied -> Notification.show("Copied " + copied),
            err    -> Notification.show("Failed: " + err.message()));
  • Fullscreen API
    Pull request

    Enter, exit, and observe fullscreen state for the whole page or a single component. Adds the Fullscreen entry point, the FullscreenBinding fluent binding, the FullscreenState enum, and per-UI server-side state synchronization.

  • Screen Wake Lock API
    Pull request

    A per-UI wake-lock facade via Page#getWakeLock() exposing request(), release(), and an active-state Signal<Boolean>. The client transparently re-acquires the lock on visibilitychange.

  • Screen Orientation API
    Pull request

    Orientation-change monitoring plus lock/unlock operations through Page.

  • Web Share API
    Pull request

    A WebShare API to invoke the browser's native share dialog, with feature detection and support for sharing dynamic content sourced from components.

Action / Trigger Framework (preview)

A new client-side trigger/action framework lets you wire browser events and inputs to server-side state and actions without hand-written JavaScript. It is intended as low level API to build higher level features on.

  • DownloadAction — trigger browser downloads from static URLs, server streams, or client-resolved values #24544
  • OpenInNewTabAction — open URLs in a new tab/window, with javascript: blocked on both sides #24545
  • CallbackAction / SetSignalAction — forward a client value back to a SerializableConsumer / a Signal on the UI thread #24455
  • SignalInput — read a server-side Signal at trigger fire time #24456
  • SizeTrigger — fire on element resize via ResizeObserver, exposing width()/height()/size() #24492
  • Public input APIsAction.Input rendering and HandlerInput are public so custom actions/triggers outside Flow can consume trigger inputs #24648

Routing and Navigation

  • UI router state signal
    Pull request

    UI.routerStateSignal() is a read-only Signal<RouterState> (current Location, RouteParameters, active chain, target class) updated atomically alongside AfterNavigationEvent, so components can observe the active route via Signal.effect instead of registering an AfterNavigationListener.

  • Route hierarchy with dynamic titles
    Pull request

    An instance-free mechanism for resolving page titles and logical route hierarchies — enabling dynamic titles and navigation aids like breadcrumbs and menus without instantiating navigation targets. Adds the @DynamicPageTitle and @RouteParent annotations, the PageTitleGenerator interface, and RouteConfiguration methods to resolve a route's parent and hierarchy statelessly.

  • Expose page-title resolution as public API
    Pull request

    Router.resolvePageTitle resolves a navigation target's title without instantiating it, applying the same generator chain used during navigation.

Reactive Signals

  • Add pageVisibilitySignal() to Page
    Pull request

    A read-only signal tracking whether the browser tab is visible+focused, visible+not-focused, or hidden.

  • Bulk insert methods for ListSignal / SharedListSignal
    Pull request

    insertAllLast, insertAllFirst, and insertAllAt apply a batch with a single notification (and transactionally for shared signals).

Components and Events

  • Add getUI() to ComponentEvent #24205 and support an explicit UI in the constructor #24262 — no more event.getSource().getUI().ifPresent(...) boilerplate.
  • Introduce HasComponentsOfType for typed child containers #24186
  • Drag-and-drop to a specific location — exposes clientX/clientY and element offsets for all D&D events #23187
  • Virtual-aware component tree traversalComponentUtil.getAllChildren / streamDescendants include virtual children (slotted helpers, overlays, routing wrapper) #24459
  • setTestId / getTestId convenience methods on Component #23775

executeJs and Client-Side JS

  • JsFunction value type for composable executeJs — build a JS function value with captured parameters (including Elements and nested JsFunctions) and pass it as a parameter, removing string-concatenated boilerplate #24374
  • Element.addJsInitializer for scoped client-side JS lifecycle #24366

Server, Session, and RPC

  • UI.triggerAfter(Duration, SerializableRunnable) — run a server task after a browser-measured delay without enabling push; the returned Registration cancels the timer #24586
  • RPC invocation listener support #24613
  • Session lock request/acquire/release events #24604

Data and Binding

  • Extract HierarchicalTreeData interface from TreeData — implement the interface to use HierarchicalTreeDataProvider without TreeData; no existing API changed #23950
  • bindItems for HasDataProvider components #23761
  • Targeted item refreshrefreshItem(newItem, oldItem) re-maps identity when signal-bound items are replaced #23913
  • Binder.setAcceptHiddenFields(boolean) — restore pre-Vaadin-25 binding of hidden fields #24139
  • fromInputStream overload with fileNameOverride #24044

Security

  • X-Frame-Options: SAMEORIGIN by default — opt into clickjacking protection out of the box; configurable via the frameOptions init parameter (empty disables it) #24589
  • URL-scheme validation in Anchor, IFrame, and Page#open — safe schemes default to http, https, mailto, tel, ftp; script-capable schemes are rejected. Each sink offers an unsafe variant (setUnsafeHref, setUnsafeSrc, openUnsafe) for trusted hard-coded URLs #24588
  • Safelist overloads on the Html component #24580
  • npm supply-chain delay — a minimum-package-age check (default 1 day) instructs npm/pnpm/bun not to install package versions newer than the threshold, mitigating freshly-published compromised releases. Configurable via Options#withMinimumPackageAgeDays(int) (0 disables) #24338, #24334

Build, Frontend, and Tooling

  • Upgrade Vite 7 → Vite 8 (Rolldown) — Vite 8 replaces esbuild/Rollup with the Rust-based Rolldown bundler #23893
  • Upgrade to TypeScript 6 #23993
  • BuildFrontend incremental build for faster development cycles #23884
  • Content-hash cache busting for @StyleSheet URLs — appends ?v-c=<hash> in production so versioned stylesheets can be cached immutable for a year #23544
  • Local web components plugin — auto-redirects polymer/* and vaadin/* imports to a project web-components/node_modules folder in dev mode #23793
  • help goal for the Maven plugin #24106
  • SignalBinding with a rich BindingContext — all Element bind methods now return a SignalBinding exposing an onChange callback with old/new value and initial-run state #23670
  • Shade ASM into flow-build-tools to avoid clashes with projects on older ASM versions #24025
  • Expose application properties to TypeScriptBootstrapModifier consumers #24073

Notable Fixes

  • Prevent deadlocks in AtmospherePushConnection on concurrent push/disconnect #24215, #24133
  • Jetty 12.1 static-resource loading — fix FileSystemNotFoundException for resources packaged in JARs (e.g. vaadinPush.js) #24283, and sanitize % in resource URLs rejected by Jetty 12 #24031
  • Handle Unicode (incl. decomposed) classpath resource paths that previously failed startup #24220
  • Detect incompatible Jackson at startup — surface a clear error instead of a cryptic NoSuchMethodError when Jackson < 3.1 is on the classpath #24009
  • Show a validation error instead of NullPointerException when null is bound to a primitive bean property #24266
  • Preserve the slot attribute for initially-invisible elements so structural CSS selectors keep working #24037
  • Stable package.json hash across Linux and Windows #24321
  • Prevent stale JAR caches under the Gradle daemon #23859 and Maven daemon (mvnd) #23863; delete flow-build-info.json after the Maven session #23945
  • Preserve scroll positions of all scrollable elements after hot-swap #23722; retain local signal values during hot-swap #23854
  • Load Image/IFrame sources backed by a DownloadHandler even inside a disabled component #24346
  • Fix NullPointerException on expired web-push subscriptions #24310
  • Numerous Signals correctness fixes — avoid duplicate/stale observers on concurrent effect revalidation #24607, prevent double effect invocation when reading the same signal multiple times #23978, and avoid false infinite-loop detection when a cached signal self-updates #24412

Testing Improvements

This release continues the migration to JUnit 5/6 (Jupiter) across the codebase — including flow-data, flow-build-tools, flow-polymer-template, and vaadin-dev-server — improving test maintainability and leveraging modern testing features.

Dependency Updates

  • ⚠️ Spring Boot updated to 4.1.0 — requires Jackson 3.1+; earlier Spring Boot 4.0.x ships Jackson 3.0 and is incompatible.
  • Vite updated to 8.0.16 (Rolldown-based), @vitejs/plugin-react to 6.0.2
  • TypeScript updated to 6.0.2
  • Node.js updated to 24.16.0
  • pnpm updated to 11.6.0
  • Tailwind CSS updated to 4.3.1
  • Jackson updated to 3.1.3
  • JUnit Jupiter updated to 6.1.0
  • TestBench updated to 25.2.0
  • Jetty updated to 12.1.9
  • Maven updated to 3.9.16
  • Guava updated to 33.6.0-jre
  • Frontend dependencies updated to latest versions

Thanks For Contributions!

@martinfrancois @wutzebaer @sclassen @adraarda23


For more details, see the full comparison on GitHub.

Don't miss a new flow release

NewReleases is sending notifications on new releases.