Installation

Install gtk-js packages in your project.

npm install @gtk-js/adwaita @gtk-js/adwaita-icons react react-dom

This gives you all GTK4 components + Adwaita components + the Adwaita theme CSS (auto-injected).

GTK4 only (no Adwaita)

npm install @gtk-js/gtk4 @gtk-js/gtk4-icons react react-dom

Use this if you want GTK4's default theme instead of Adwaita. You'll need to provide your own theme CSS via GtkProvider's cssHref or cssText prop.

Provider Setup

Wrap your app in a provider at the root:

import { AdwaitaProvider } from "@gtk-js/adwaita";
import * as icons from "@gtk-js/adwaita-icons";

function App() {
  return (
    <AdwaitaProvider icons={icons}>
      {/* Your app here */}
    </AdwaitaProvider>
  );
}

The provider:

  • Injects the theme CSS (Adwaita or GTK4 default)
  • Injects the CSS reset (strips browser defaults inside the provider boundary)
  • Injects layout CSS (flexbox/grid classes for GTK layout managers)
  • Provides icon context (widgets load icons from the provider's icon set)
  • Provides theme context (accent color, color scheme, high contrast)
  • Hides its content until it's ready (see below)

Server rendering

With React 19, the provider renders the reset, layout and theme CSS into server-rendered or static HTML (as hoisted <style> elements, once per page), so the content is styled from its first paint; on hydration the provider takes those elements over. React 18 can't hoist them, so there the CSS is injected from JavaScript.

Part of GTK's layout (computed expand) runs in JavaScript too, so the provider keeps server-rendered content laid out but invisible (visibility: hidden, aria-busy) until it has hydrated, and reveals it before the next paint. With the CSS in the HTML, the hidden content already has its final size. A client-only render is ready before its first paint, so it's never hidden; only a cssHref stylesheet that's still loading holds it back (for up to 3 seconds). With JavaScript disabled, a <noscript> style shows the content as is.

To paint server-rendered content right away instead, pass hideUntilReady={false}.

A theme can also be a stylesheet file: cssHref links it (<link precedence> in server HTML), and cssText with it is CSS that goes after it, such as an accent color. A new cssHref replaces the old stylesheet once it has loaded, with transitions off. To show a theme the user picked from the first frame, a script in <head> can link it before React runs, as <link rel="stylesheet" id="gtk-js-theme"> (and <style id="gtk-js-theme-text"> after it); a provider given that cssHref takes them over. These docs do that with their theme picker.

On this page