NEWGTKX 2.0 beta: a smaller, safer foundation

// 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.

src/index.tsx
import {
  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.

gtkx.config.ts
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.

src/app.tsx
<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.

package.json
{
  "dependencies": {
    "@gtkx/react": "*",
    "react": "*",
    "zod": "*",
    "zustand": "*"
  }
}

One CLI for the whole lifecycle

bash
npm create gtkx
◇ Project structure created
◇ Dependencies installed
◇ Git repository initialized

A comprehensive tutorial

The docs walk you through creating Tasks, a complete GNOME app: adaptive split view, GSettings, notifications, and shipped as a Flatpak.

The Tasks app built in the tutorial: an adaptive Adwaita window with a sidebar of smart views and colored lists next to a boxed task list.Follow the tutorial

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.