Skip to main content

Getting Started

This guide walks you through creating your first GTKX application.

Prerequisites

Before you begin, ensure you have:

  • Node.js 22+ — GTKX requires a modern Node.js runtime
  • GTK4 libraries — The native GTK4 runtime libraries

Create a New Project

The fastest way to start is with the GTKX CLI:

npx @gtkx/cli create my-app

The CLI will prompt you for:

  • Project name — lowercase letters, numbers, and hyphens
  • App ID — reverse domain notation (e.g., com.example.myapp)
  • Package manager — pnpm (recommended), npm, or yarn
  • Testing — whether to include Vitest testing setup

After the prompts, the CLI creates your project and installs dependencies.

Project Structure

A new GTKX project has this structure:

my-app/
├── src/
│ ├── app.tsx # Main application component
│ ├── dev.tsx # Development entry point
│ └── index.tsx # Production entry point
├── tests/
│ └── app.test.tsx # Example test
├── package.json
└── tsconfig.json

Key Files

src/app.tsx — Your main React component:

import { useState } from "react";
import * as Gtk from "@gtkx/ffi/gtk";
import {
GtkApplicationWindow,
GtkBox,
GtkButton,
GtkLabel,
quit,
} from "@gtkx/react";

export default function App() {
const [count, setCount] = useState(0);

return (
<GtkApplicationWindow
title="My App"
defaultWidth={400}
defaultHeight={300}
onClose={quit}
>
<GtkBox
orientation={Gtk.Orientation.VERTICAL}
spacing={20}
marginTop={40}
marginStart={40}
marginEnd={40}
>
Welcome to GTKX!
<GtkLabel label={`Count: ${count}`} />
<GtkButton label="Increment" onClicked={() => setCount((c) => c + 1)} />
</GtkBox>
</GtkApplicationWindow>
);
}

src/index.tsx — Production entry point:

import { render } from "@gtkx/react";
import pkg from "../package.json" with { type: "json" };
import App from "./app.js";

render(<App />, pkg.gtkx.appId);

package.json — Contains your app ID in the gtkx config:

{
"gtkx": {
"appId": "com.example.myapp"
}
}

Run the Development Server

Start the development server with hot reload:

npm run dev

This starts your application with Hot Module Replacement (HMR). When you edit your components, changes appear instantly without losing application state.

Build for Production

Compile your TypeScript and prepare for distribution:

npm run build
npm start

Run Tests

If you enabled testing:

npm test

Tests run in a real GTK environment using the @gtkx/vitest plugin, which automatically manages Xvfb displays for headless execution.

Understanding the Basics

Components Map to Widgets

GTKX components correspond to GTK widgets. The naming convention:

  • GTK widgets: GtkButton, GtkLabel, GtkBox, GtkEntry
  • Adwaita widgets: AdwHeaderBar, AdwViewStack, AdwActionRow

Props Set Widget Properties

Component props map to GTK widget properties:

<GtkButton
label="Click me" // Sets the button label
sensitive={false} // Disables the button
cssClasses={["suggested-action"]} // Adds CSS classes
/>

Callbacks Handle Signals

GTK signals become React callbacks with an on prefix:

<GtkButton
onClicked={() => console.log("clicked")} // "clicked" signal
/>

<GtkEntry
onChanged={() => console.log("text changed")} // "changed" signal
/>

GTK Enums

GTK enums come from the FFI package:

import * as Gtk from "@gtkx/ffi/gtk";

<GtkBox orientation={Gtk.Orientation.VERTICAL} />
<GtkLabel halign={Gtk.Align.CENTER} />

What's Next?