How to Build Modern Java Desktop Apps with Shadcn UI, React, and JxBrowser

This article explains why traditional Java UI toolkits fall short, then walks through a complete solution that embeds a React + shadcn/ui front‑end inside a Java desktop window using JxBrowser, covering window creation, resource loading for dev and production, and two Java‑Web communication strategies (JS‑Java bridge and Protobuf + gRPC).

SpringMeng
SpringMeng
SpringMeng
How to Build Modern Java Desktop Apps with Shadcn UI, React, and JxBrowser

Swing/JavaFX Limitations

Java native UI toolkits (Swing, JavaFX, SWT) have three major drawbacks: difficult UI customization, a sparse component ecosystem, and an outdated visual style that has not changed for a decade. Web UI provides abundant component libraries, built‑in high‑DPI, touch and responsive support, and cross‑platform visual consistency.

Overall Solution: JxBrowser + React + shadcn/ui

The goal is to build a preferences dialog that persists user settings to the local file system and restores them on restart. The stack combines a Chromium‑based JxBrowser view, a React application styled with shadcn/ui, and TypeScript.

Window and Web View

A JFrame is created and a JxBrowser Chromium view is embedded inside it:

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

Development

A development server provides hot‑reloading. The browser loads the UI from the local server:

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

Production

Running a dev server in production adds an extra process and exposes source files via localhost. The solution packages web assets into the JAR and serves them through a custom jxb:// scheme using JxBrowser’s request interceptor:

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

Navigation then loads resources from the classpath:

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

Java ↔ Web Communication

Two approaches are presented for the web front‑end to invoke Java code that reads or writes preference files.

Option 1: JS‑Java Bridge (small projects)

JxBrowser allows JavaScript to call annotated Java methods directly:

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

This works for a few calls but lacks compile‑time checks and IDE completion as the interface grows.

Option 2: Protobuf + gRPC (serious projects)

A .proto file defines a type‑safe API, generating Java and TypeScript stubs:

service PrefsService {
    rpc SetFontSize(FontSize) returns (google.protobuf.Empty);
}

enum FontSize {
    SMALL = 0;
    DEFAULT = 1;
    LARGE = 2;
}

The Java side runs a gRPC server, while the web side uses a Connect client:

// Java server
class PrefsService extends PrefsServiceImplBase {
    @Override
    public void setTheme(Theme request, StreamObserver<Empty> responseObserver) { }
}
// TypeScript client
const transport = createGrpcWebTransport({
    baseUrl: `http://localhost:50051`,
});
const prefsClient = createClient(PrefsService, transport);
prefsClient.setFontSize(FontSize.SMALL);

Benefits include type safety, automatic code generation, IDE autocomplete, and compile‑time validation, which become increasingly valuable as the project scales.

Reference

Full source code is available on GitHub: 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.

JavaReActgRPCProtobufdesktopShadcn UIJxBrowser
SpringMeng
Written by

SpringMeng

Focused on software development, sharing source code and tutorials for various systems.

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.