How to Build a Cross‑Platform Java Desktop App with React and shadcn/ui

This article explains how to embed modern web UI built with React, TypeScript, and shadcn/ui into a Java desktop application using JxBrowser, covering reliable web view integration, server‑less resource loading, and bidirectional Java‑JavaScript communication via bridges or gRPC.

Java Captain
Java Captain
Java Captain
How to Build a Cross‑Platform Java Desktop App with React and shadcn/ui

Swing/JavaFX Limitations

UI pain points: modern animations require custom implementation.

Ecosystem desert: few component libraries, low community activity, hiring difficulty.

Outdated look: default controls appear decade‑old.

Overall Solution: JxBrowser + React + shadcn/ui

The goal is a preferences dialog that persists settings to the local file system and restores them on restart.

Three core challenges:

Reliable web view: Java’s built‑in WebView lags behind modern web standards.

Server‑less loading: production must not depend on a local or remote server.

Java ↔ JS communication: file‑system operations should bypass a web server.

Window and Web View

Use a Swing JFrame as the native window and embed a Chromium‑based view provided by JxBrowser:

var engine = Engine.newInstance(HARDWARE_ACCELERATED);
var browser = engine.newBrowser();
SwingUtilities.invokeLater(() -> {
    var view = BrowserView.newInstance(browser);
    var frame = new JFrame("Application");
    frame.addWindowListener(new WindowAdapter() {
        @Override
        public void windowClosing(WindowEvent e) {
            engine.close();
        }
    });
    frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    frame.add(view, BorderLayout.CENTER);
    frame.setSize(1280, 900);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
});

Resource Loading: Development vs Production

During development a dev server provides hot‑reloading:

./gradlew startDevServer
if (!AppDetails.isProduction()) {
    browser.navigation().loadUrl("http://localhost:[port]");
}

In production package all web assets into the JAR and serve them via a custom jxb:// scheme using a request interceptor:

var options = EngineOptions.newBuilder(HARDWARE_ACCELERATED)
    .addScheme(Scheme.of("jxb"), new UrlRequestInterceptor())
    .build();
var engine = Engine.newInstance(options);

Load resources:

if (!AppDetails.isProduction()) {
    browser.navigation().loadUrl("http://localhost:[port]");
} else {
    browser.navigation().loadUrl("jxb://my-app.com");
}

The interceptor returns index.html, CSS, and JS files from the classpath, keeping all resources internal while normal HTTPS/API calls continue to work.

Java ↔ Web Communication

Two approaches to invoke Java from the web front‑end:

Option 1: JS‑Java Bridge (small projects)

@JsAccessible
class PrefsService {
    void setFontSize(int size) { }
}
// TypeScript side
declare class PrefsService {
    setFontSize(size: number): void;
}
prefsService.setFontSize(12);

Simple but lacks compile‑time checks as the API grows.

Option 2: Protobuf + gRPC (large projects)

service PrefsService {
    rpc SetFontSize(FontSize) returns (google.protobuf.Empty);
}
enum FontSize {
    SMALL = 0;
    DEFAULT = 1;
    LARGE = 2;
}

Run a gRPC server on the Java side and connect from the web side using a Connect client:

// Java server
class PrefsService extends PrefsServiceImplBase { /* implementation */ }
// TypeScript client
const transport = createGrpcWebTransport({ baseUrl: `http://localhost:50051` });
const prefsClient = createClient(PrefsService, transport);
prefsClient.setFontSize(FontSize.SMALL);

The gRPC approach provides type safety, automatic code generation, IDE completion, and compile‑time validation.

References

GitHub repository with the full source code: https://github.com/TeamDev-IP/JxBrowser-Gallery

ReActWebViewgRPCProtobufDesktop UIJxBrowser
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.