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

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

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.