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

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.