In a recent blog post, I debunked the myth that a Web Component is essential as a counterpart to your Vaadin Java component. The Element API in Vaadin Flow is also apt for raw JS components. Given that React components are JS components, it's feasible to wrap them directly. However, React's unique JSX/TSX syntax extension and stature as arguably the most popular front-end library merits a dedicated example and article.
I demonstrated this by wrapping a generic color picker component named Colorful into a Java component. Beyond wrapping generic components, these principles are equally applicable if you intend to incorporate larger existing React views into your Vaadin application or delegate one section of your Vaadin app development to a React developer. This mirrors the situation one community member found themselves in, aiming to repurpose parts of their mobile app (built with Capacitor & React) within their Vaadin-based web UI.
Compiling JSX/TSX files
React isn't limited to JSX; it also accommodates plain JS. Interestingly, my initial example skipped JSX entirely. I anticipated complications with JSX compilation or, at the very least, having to tweak the front-end build managed by Vaadin. However, given JSX's prevalence in the React ecosystem, even a developer prone to borrowing code (like myself 🤓) finds it indispensable.
I decided to experiment: I changed the "connector script file" extension to .jsx and incorporated JSX elements. To my astonishment, it worked seamlessly. The Vite build tool, currently utilized by Vaadin for frontend development, inherently supports JSX. I'd recommend using the TSX format, especially in file suffixes. This allows for optional TypeScript use in your connector and ensures compatibility when packaging as an add-on with slightly older Vaadin versions (I've submitted a PR to support .jsx too).
Place the JSX/TSX file in the same location as the other JS files you import with the @JsModule
annotation. Several directories will do, but I advocate for src/main/resources/META-INF/frontend by default. This is convenient for standard apps and sets you up should you later migrate your integration to a separate module or even share it with the Vaadin community.
Data transfer between client & server
For Web Component integrations, developers typically rely on DOM attributes & properties via the Element API to synchronize the state between the Java component and its client-side counterpart. With React components, that approach doesn't hold water. Instead, raw JS calls are essential for data relay. In the constructor, we send the initial value to the "connector method." When the server-side API adjusts the color value, we relay the update via a hook created in the connector method.
To update the Java component with a new color selected by the user, the most straightforward approach is to invoke a server-side method exposed with the @ClientCallable
annotation directly. In my example, I demonstrated a slightly more intricate but versatile method. Some components might frequently refresh their values, triggering substantial client-server traffic. By employing custom JS events from the connector for value relay, Vaadin's in-built features can effectively debounce the input.
Is an NPM build necessary?
For this method: unequivocally, yes. Front-end tools are imperative both during add-on development and its subsequent application. They cater to JSX compilation and dependency management.
Vaadin 24.1 introduced a pre-built front-end package feature, which was met with widespread acclaim, myself included. Given the intricate nature of React integrations, I'd advise against aiming for this if React is involved. However, the efficiencies from the dev-bundle should minimize the need for repeated front-end builds within your team. In case you absolutely need an add-on without triggering a front-end build, it's achievable with these steps:
- Integrate React libraries and the component into the page, bypassing the
@NpmPackage
annotation (e.g., download them to your project and employ the@JavaScript
annotation). - Exclude JSX in favor of raw JS API for React component rendering. Refer to my first version of the Colorful add-on for guidance.
- Introduce the "connector script" using
@JavaScript
annotation, replacing@JsModule
. - Abandon imports (since it's no longer perceived as a JavaScript module) and rely on complete references to the React API. These instructions might help.
Access the example code or add-on
The source code for my demo is accessible on GitHub. Feel free to explore it if you're considering embedding React components or full views within your Vaadin application. If you're on the hunt for a sophisticated color picker widget with an intuitive Java API, peruse the packaged add-on in the Vaadin Directory.