Building a Java Desktop App with Shadcn UI, React, and JxBrowser
The article explains how to replace outdated Swing/JavaFX UI by embedding a React application styled with shadcn/ui into a Java desktop program using JxBrowser, covering reliable web view setup, dev‑vs‑prod resource loading via a custom jxb:// scheme, and two Java‑to‑JS communication approaches (JS‑Java bridge and Protobuf + gRPC) with concrete code examples.
Swing/JavaFX Limitations
UI Pain : implementing modern animations requires custom work.
Ecosystem Desert : few component libraries, low community activity, hiring difficulty.
Outdated Look : default widgets appear dated.
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. The UI is a standard React application styled with shadcn/ui and TypeScript. The Java side creates a Chromium‑based web view using 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 the React dev server runs locally, and the browser loads http://localhost:<port>:
./gradlew startDevServer
if (!AppDetails.isProduction()) {
browser.navigation().loadUrl("http://localhost:[port]");
}In production a dev server cannot be used because it adds an extra process and exposes source code. A custom jxb:// scheme intercepts requests and serves bundled resources from the JAR classpath:
var options = EngineOptions.newBuilder(HARDWARE_ACCELERATED)
.addScheme(Scheme.of("jxb"), new UrlRequestInterceptor());
var engine = Engine.newInstance(options.build());When the browser navigates to jxb://my-app.com, the interceptor returns index.html and subsequent CSS/JS files from internal resources, keeping all loading internal and preserving normal HTTPS/API calls.
Java ↔ Web Communication
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);This works when the API surface is tiny, but as the number of methods grows there is no compile‑time checking or IDE auto‑completion, leading to higher maintenance cost.
Option 2 – Protobuf + gRPC (serious projects)
service PrefsService {
rpc SetFontSize(FontSize) returns (google.protobuf.Empty);
}
enum FontSize {
SMALL = 0;
DEFAULT = 1;
LARGE = 2;
} class PrefsService extends PrefsServiceImplBase {
@Override
public void setTheme(Theme request, StreamObserver<Empty> responseObserver) { }
} const transport = createGrpcWebTransport({
baseUrl: `http://localhost:50051`,
});
const prefsClient = createClient(PrefsService, transport);
prefsClient.setFontSize(FontSize.SMALL);This approach provides type safety, automatic code generation, IDE completion, and compile‑time checks, making it far more suitable for larger codebases.
Reference
Full source code is available on GitHub: https://github.com/TeamDev-IP/JxBrowser-Gallery
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Java Architect Handbook
Focused on Java interview questions and practical article sharing, covering algorithms, databases, Spring Boot, microservices, high concurrency, JVM, Docker containers, and ELK-related knowledge. Looking forward to progressing together with you.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
