// React · Node · TypeScript · libadwaita · GTK4
The React framework for Linux
Build native GNOME applications with React and TypeScript. GTKX puts libadwaita first and brings the whole platform to standard web tooling.
npm create gtkximport {
AdwApplication, AdwApplicationWindow,
AdwHeaderBar, AdwToolbarView,
} from "@gtkx/jsx/adw";
import { GtkLabel } from "@gtkx/jsx/gtk";
import { createRoot, quit } from "@gtkx/react";
const App = () => (
<AdwApplication>
<AdwApplicationWindow title="My App" onCloseRequest={() => quit()}>
<AdwToolbarView topBar={<AdwHeaderBar />}>
<GtkLabel>Hello from GNOME 👋</GtkLabel>
</AdwToolbarView>
</AdwApplicationWindow>
</AdwApplication>
);
createRoot().render(<App />);GNOME in JSX
libadwaita, GTK4, and every GObject-derived class are available through typed JSX. Compose the whole native object graph declaratively.
Hot reload for desktop
Fast Refresh patches the running window as you save. Changes it cannot patch trigger an automatic, supervised restart.
Typed end to end
Every class, signal, enum and property is generated from GIRs and available to your IDE with full type information.
Test native GNOME apps
Query and drive real Adwaita and GTK4 widgets in Vitest, with a virtual display running on a headless Wayland compositor.
Agentic MCP server
A Model Context Protocol (MCP) server exposes your live app to AI agents, enabling testing, debugging and even autonomous development.
Powered by Rust
A native Rust core translates your GLib/GObject calls to the native architecture at runtime.
GNOME apps in JSX, rendered as GObjects
Start with the GNOME platform
libadwaita over GTK4 is the foundation. Name any additional GIRs and codegen reads them off your system, emitting typed bindings for exactly those namespaces too.
import { defineConfig } from "@gtkx/config";
export default defineConfig({
applicationId: "com.example.myapp",
libraries: ["WebKit-6.0"],
future: { v2DefaultLibraries: true },
});If it is a GObject, you can write it in JSX
Element types are GObject type names. Nested GObjects go in props, so a header bar or an adjustment is an element too, not an object you build on the side.
<AdwToolbarView topBar={<AdwHeaderBar />}>
<GtkScale
adjustment={<GtkAdjustment upper={100} />}
drawValue
/>
</AdwToolbarView>Vanilla Node, real npm
Your app is a plain Node program, so every npm package and Node API is available to it.
{
"dependencies": {
"@gtkx/react": "*",
"react": "*",
"zod": "*",
"zustand": "*"
}
}One CLI for the whole lifecycle
npm create gtkx◇ Project structure created◇ Dependencies installed◇ Git repository initializedA comprehensive tutorial
The docs walk you through creating Tasks, a complete GNOME app: adaptive split view, GSettings, notifications, and shipped as a Flatpak.

Built in the open
GTKX is MPL-2.0-licensed and developed in public. We're open to contributions, and we welcome feedback and questions on GitHub.