Skip to content

Adwaita

Adwaita is GNOME’s design system for GTK 4: the rows, buttons, header bars and dialogs a GNOME app is made of. GJSify gives you the whole set from TypeScript, and the same widget renders as a real Libadwaita widget on the desktop and as a custom element in the browser.

Pick a category below. Every widget on those pages runs live in your browser, in a window whose second tab holds the markup that paints it, followed by one window per kind of implementation: Native TypeScript, the @girs program that runs unchanged on GJS, Node, Bun and Deno, with a Blueprint declaration beside it, UI frameworks, the same widget written in Solid, Vue and React through @gjsify/gtk-host, and NativeScript, the port that runs on a phone, whose XML template holds the tree with the TypeScript beside it as the loader. Choose a tab once and every widget block on the site follows it.

Adwaita is one design system GJSify supports, not a requirement. Your app is an ordinary GTK 4 program, so you can mix in plain Gtk.* widgets or style your own, and the browser components live in a package you opt into. Libadwaita ships no entry, drop down, plain button or menu button, and those GTK widgets are documented under Gtk.

On the desktop the widgets come from the Libadwaita library already installed on the machine. @girs/adw-1 is the type package for it, and nothing else is needed:

TypeScript
import Adw from 'gi://Adw?version=1';
const row = new Adw.SwitchRow({ title: 'Automatic updates', active: true });

For the browser, install the port and import it once. That registers every element and applies the stylesheet, so from there you write HTML:

Terminal
gjsify install @gjsify/adwaita-web
TypeScript
import '@gjsify/adwaita-web';
HTML
<adw-preferences-group title="Updates">
<adw-switch-row title="Automatic updates" active></adw-switch-row>
</adw-preferences-group>

The package entry is TypeScript, so it goes through your bundler like any other dependency: gjsify build --app browser, the gjsifyBrowser() Vite preset, or whatever you already use.

To change how any of it looks, set the design tokens.

On the desktop

Real Libadwaita widgets, typed by @girs/adw-1: Adw.SwitchRow, Adw.HeaderBar, Adw.NavigationSplitView. This is the reference the other two ports follow, and the code runs unchanged on GJS, Node.js, Bun and Deno.

In the browser

@gjsify/adwaita-web gives you the same widgets as custom elements: <adw-switch-row>, <adw-header-bar>. There is no runtime framework to learn: one import registers everything, and then you write HTML.

On Android and iOS

@gjsify/adwaita-nativescript reproduces the Adwaita look with real NativeScript views rather than a webview: AdwSwitchRow, AdwHeaderBar. Some widgets are simplified, and each page says where.

The web and NativeScript ports share one behaviour layer, so a fix to a toast queue or a spin-button clamp lands in both at once. If you want the mechanics, see How It Works.

The Adwaita Storybook is a component browser: pick a widget, change its properties from a controls panel, and watch it update. Run it as a native window with gjsify storybook, or use the version embedded on that page.

Ready to assemble a whole app out of these? Start with Native Adwaita Apps.