Introduction
GTKX is a framework for building native GTK4 desktop applications using React and TypeScript. It bridges React's component model with GTK4's native widget system, allowing you to write familiar React code that renders as native Linux desktop applications.
Why GTKX?
Building native desktop applications traditionally requires learning platform-specific toolkits and languages. GTKX changes this by letting you use the React skills you already have:
- Familiar React Patterns — Use hooks, state, props, and components just like you would in a web app
- Type Safety — Full TypeScript support with auto-generated types from GTK4's introspection data
- Native Performance — Direct FFI bindings to GTK4 via Rust and libffi, no Electron overhead
- Modern Tooling — Works with your existing Node.js toolchain, testing frameworks, and build tools
How It Works
GTKX uses a custom React Reconciler to translate React's virtual DOM operations into GTK4 widget operations:
React JSX → React Reconciler → FFI Bindings → GTK4 Widgets
- You write React components using JSX
- The GTKX reconciler converts React elements into GTK widget nodes
- TypeScript FFI bindings marshal calls to native GTK4 via Rust
- GTK4 renders native widgets on your Linux desktop
Packages
GTKX is organized as a monorepo with the following packages:
| Package | Description |
|---|---|
@gtkx/react | React reconciler and JSX components |
@gtkx/ffi | TypeScript FFI bindings for GTK4, GLib, GIO, Gdk, and more |
@gtkx/css | CSS-in-JS styling for GTK widgets (Emotion-style API) |
@gtkx/testing | Testing utilities with a Testing Library-style API |
@gtkx/native | Rust native module providing the FFI bridge |
@gtkx/gir | GObject Introspection parser for code generation |
Example
Here's a simple counter application:
import { render, ApplicationWindow, Box, Button, Label, quit } from "@gtkx/react";
import { Orientation } from "@gtkx/ffi/gtk";
import { useState } from "react";
const Counter = () => {
const [count, setCount] = useState(0);
return (
<Box orientation={Orientation.VERTICAL} spacing={12} margin={20}>
<Label.Root label={`Count: ${count}`} />
<Button label="Increment" onClicked={() => setCount(c => c + 1)} />
</Box>
);
};
const App = () => (
<ApplicationWindow title="Counter" defaultWidth={300} defaultHeight={150} onCloseRequest={quit}>
<Counter />
</ApplicationWindow>
);
render(<App />, "org.example.Counter");
Next Steps
- Getting Started — Install GTKX and create your first app
- Styling Guide — Style your app with CSS-in-JS
- Testing Guide — Write tests for your components