Skip to content

Boxed Lists

Reach for a boxed list whenever you build a settings or detail screen: a set of related rows gathered into one rounded card. The card is a preferences group, and each row is a small self-contained control (a toggle, a text field, a drop-down, a button).

Each block below is a stack of windows. The first one RUNS the widget: the preview is the live browser port, so it follows the light and dark toggle the way a real window would, and the HTML tab beside it holds the very markup that paints it — one import '@gjsify/adwaita-web' registers every element in it. Then comes one window per kind of implementation — Native TypeScript, the @girs program that runs unchanged on GJS, Node, Bun and Deno, with the matching Blueprint declaration beside it, UI frameworks, the same widget written in Solid, Vue and React through @gjsify/gtk-host — or, where the widget is built imperatively rather than declared, the recorded reason it has no such snippet — and NativeScript, the port that runs on a phone. That last window splits the way the first one does. An XML template holds the tree, and the TypeScript beside it is the loader.

Libadwaita is the reference here, typed by @girs/adw-1. @gjsify/adwaita-web and @gjsify/adwaita-nativescript follow its naming, and where one of them differs, its own window says so.

Start with the group: it draws its rows as one rounded card. Give it a title, a description, and a header-suffix widget (a button or switch pinned to the trailing edge of the header). Stack several groups to build a full preferences page.

Adw.PreferencesGroup
HTML
<adw-preferences-group title="Account" description="Manage how this device signs in and syncs.">
<button slot="header-suffix" class="adw-button flat">Sign out</button>
<adw-entry-row title="Display name" text="Grace Hopper"></adw-entry-row>
<adw-switch-row title="Sync over Wi-Fi only" subtitle="Avoid using mobile data for backups" active></adw-switch-row>
<adw-combo-row title="Region" items='["Europe","Americas","Asia","Oceania"]' selected="0"></adw-combo-row>
</adw-preferences-group>
<adw-preferences-group> observes these in the browser port. Changing one re-renders the element. The second column is what the preview one tab to the left writes, read across every copy of the element in it. The other windows name their own properties.
Attribute In this preview
title Account
description Manage how this device signs in and syncs.
Native TypeScript
TypeScript
import Adw from 'gi://Adw?version=1';
import Gtk from 'gi://Gtk?version=4.0';
const signOut = new Gtk.Button({ label: 'Sign out', valign: Gtk.Align.CENTER });
signOut.add_css_class('flat');
const group = new Adw.PreferencesGroup({
title: 'Account',
description: 'Manage how this device signs in and syncs.',
headerSuffix: signOut,
});
group.add(new Adw.EntryRow({ title: 'Display name', text: 'Grace Hopper' }));
group.add(new Adw.SwitchRow({ title: 'Sync over Wi-Fi only', active: true }));
Code
using Gtk 4.0;
using Adw 1;
Adw.PreferencesGroup {
title: _("Account");
description: _("Manage how this device signs in and syncs.");
header-suffix: Gtk.Button {
label: _("Sign out");
styles ["flat"]
};
Adw.EntryRow {
title: _("Display name");
text: "Grace Hopper";
}
Adw.SwitchRow {
title: _("Sync over Wi-Fi only");
subtitle: _("Avoid using mobile data for backups");
active: true;
}
Adw.ComboRow {
title: _("Region");
selected: 0;
model: Gtk.StringList {
strings [_("Europe"), _("Americas"), _("Asia"), _("Oceania")]
};
}
}
UI frameworks
TypeScript
// mount(() => <AdwPreferencesGroup />, container) — from '@gjsify/gtk-host/solid'
const AdwPreferencesGroup = () => (
<adw-preferences-group
title="Account"
description="Manage how this device signs in and syncs."
>
<adw-entry-row
title="Display name"
text="Grace Hopper"
/>
<adw-switch-row
title="Sync over Wi-Fi only"
subtitle="Avoid using mobile data for backups"
active
/>
</adw-preferences-group>
);
Vue
<!-- AdwPreferencesGroup.vue — mount(AdwPreferencesGroup, container) from '@gjsify/gtk-host/vue' -->
<template>
<adw-preferences-group
title="Account"
description="Manage how this device signs in and syncs."
>
<adw-entry-row
title="Display name"
text="Grace Hopper"
/>
<adw-switch-row
title="Sync over Wi-Fi only"
subtitle="Avoid using mobile data for backups"
:active="true"
/>
</adw-preferences-group>
</template>
TypeScript
// createRoot(container).render(<AdwPreferencesGroup />) — from '@gjsify/gtk-host/react'
const AdwPreferencesGroup = () => (
<adw-preferences-group
title="Account"
description="Manage how this device signs in and syncs."
>
<adw-entry-row
title="Display name"
text="Grace Hopper"
/>
<adw-switch-row
title="Sync over Wi-Fi only"
subtitle="Avoid using mobile data for backups"
active
/>
</adw-preferences-group>
);
NativeScript
TypeScript
import { AdwPreferencesGroup, AdwEntryRow, AdwSwitchRow } from '@gjsify/adwaita-nativescript';
const group = new AdwPreferencesGroup();
group.title = 'Account';
group.description = 'Manage how this device signs in and syncs.';
const name = new AdwEntryRow();
name.title = 'Display name';
name.text = 'Grace Hopper';
group.addRow(name);
const sync = new AdwSwitchRow();
sync.title = 'Sync over Wi-Fi only';
sync.active = true;
group.addRow(sync);
XML
<adw:AdwPreferencesGroup
xmlns="http://schemas.nativescript.org/tns.xsd"
xmlns:adw="~/adwaita"
title="Account"
description="Manage how this device signs in and syncs."
>
<adw:AdwEntryRow
title="Display name"
text="Grace Hopper"
/>
<adw:AdwSwitchRow
title="Sync over Wi-Fi only"
subtitle="Avoid using mobile data for backups"
active="true"
/>
</adw:AdwPreferencesGroup>

The general-purpose row: a title with an optional subtitle, plus prefix and suffix slots for extra widgets (an icon on the leading edge, a button or chevron on the trailing edge). Mark it activatable and the whole row responds to a click, which is how you open a detail page.

Adw.ActionRow
HTML
<adw-preferences-group>
<adw-action-row title="Wi-Fi" subtitle="Connected to Highgarden 5GHz" activatable>
<span slot="prefix" class="adw-icon adw-icon--network-wireless"></span>
<gtk-button slot="suffix" icon="go-next" flat></gtk-button>
</adw-action-row>
</adw-preferences-group>
<adw-action-row> observes these in the browser port. Changing one re-renders the element. The second column is what the preview one tab to the left writes, read across every copy of the element in it. The other windows name their own properties.
Attribute In this preview
title Wi-Fi
subtitle Connected to Highgarden 5GHz
activatable set
Native TypeScript
TypeScript
import Adw from 'gi://Adw?version=1';
import Gtk from 'gi://Gtk?version=4.0';
const row = new Adw.ActionRow({
title: 'Wi-Fi',
subtitle: 'Connected to Highgarden 5GHz',
});
row.add_prefix(new Gtk.Image({ iconName: 'network-wireless-symbolic' }));
const next = new Gtk.Button({ iconName: 'go-next-symbolic', valign: Gtk.Align.CENTER });
next.add_css_class('flat');
row.add_suffix(next);
row.activatableWidget = next;
row.activatable = true;
Code
using Gtk 4.0;
using Adw 1;
Adw.PreferencesGroup {
Adw.ActionRow {
title: _("Wi-Fi");
subtitle: _("Connected to Highgarden 5GHz");
activatable: true;
[prefix]
Gtk.Image {
icon-name: "network-wireless-symbolic";
}
[suffix]
Gtk.Image {
icon-name: "go-next-symbolic";
}
}
}
UI frameworks
TypeScript
// mount(() => <AdwActionRow />, container) — from '@gjsify/gtk-host/solid'
const AdwActionRow = () => (
<adw-preferences-group>
<adw-action-row
title="Wi-Fi"
subtitle="Connected to Highgarden 5GHz"
activatable
>
<gtk-image
slot="prefix"
iconName="network-wireless-symbolic"
/>
<gtk-button
slot="suffix"
iconName="go-next-symbolic"
cssClasses={['flat']}
valign="center"
/>
</adw-action-row>
</adw-preferences-group>
);
Vue
<!-- AdwActionRow.vue — mount(AdwActionRow, container) from '@gjsify/gtk-host/vue' -->
<template>
<adw-preferences-group>
<adw-action-row
title="Wi-Fi"
subtitle="Connected to Highgarden 5GHz"
:activatable="true"
>
<gtk-image
slot="prefix"
icon-name="network-wireless-symbolic"
/>
<gtk-button
slot="suffix"
icon-name="go-next-symbolic"
:css-classes="['flat']"
valign="center"
/>
</adw-action-row>
</adw-preferences-group>
</template>
TypeScript
// createRoot(container).render(<AdwActionRow />) — from '@gjsify/gtk-host/react'
const AdwActionRow = () => (
<adw-preferences-group>
<adw-action-row
title="Wi-Fi"
subtitle="Connected to Highgarden 5GHz"
activatable
>
<gtk-image
slot="prefix"
iconName="network-wireless-symbolic"
/>
<gtk-button
slot="suffix"
iconName="go-next-symbolic"
cssClasses={['flat']}
valign="center"
/>
</adw-action-row>
</adw-preferences-group>
);
NativeScript
TypeScript
import { AdwActionRow, AdwIcon } from '@gjsify/adwaita-nativescript';
import { goNextSymbolic } from '@gjsify/adwaita-icons/actions';
import { networkWirelessSymbolic } from '@gjsify/adwaita-icons/devices';
const row = new AdwActionRow();
row.title = 'Wi-Fi';
row.subtitle = 'Connected to Highgarden 5GHz';
const icon = new AdwIcon();
icon.iconName = networkWirelessSymbolic; // an Adwaita symbolic icon (SVG string)
row.setPrefix(icon);
const chevron = new AdwIcon();
chevron.iconName = goNextSymbolic;
row.setSuffix(chevron);
XML
<adw:AdwPreferencesGroup
xmlns="http://schemas.nativescript.org/tns.xsd"
xmlns:adw="~/adwaita"
>
<adw:AdwActionRow
title="Wi-Fi"
subtitle="Connected to Highgarden 5GHz"
activatable="true"
/>
</adw:AdwPreferencesGroup>

An action row with a trailing switch, for a single on/off setting. This is the row you will use most in a preferences page.

Adw.SwitchRow
HTML
<adw-preferences-group>
<adw-switch-row title="Automatic updates" subtitle="Download and install updates without asking" active></adw-switch-row>
</adw-preferences-group>
<adw-switch-row> observes these in the browser port. Changing one re-renders the element. The second column is what the preview one tab to the left writes, read across every copy of the element in it. The other windows name their own properties.
Attribute In this preview
title Automatic updates
subtitle Download and install updates without asking
active set
Native TypeScript
TypeScript
import Adw from 'gi://Adw?version=1';
const row = new Adw.SwitchRow({
title: 'Automatic updates',
subtitle: 'Download and install updates without asking',
active: true,
});
Code
using Gtk 4.0;
using Adw 1;
Adw.PreferencesGroup {
Adw.SwitchRow {
title: _("Automatic updates");
subtitle: _("Download and install updates without asking");
active: true;
}
}
UI frameworks
TypeScript
// mount(() => <AdwSwitchRow />, container) — from '@gjsify/gtk-host/solid'
const AdwSwitchRow = () => (
<adw-preferences-group>
<adw-switch-row
title="Automatic updates"
subtitle="Download and install updates without asking"
active
/>
</adw-preferences-group>
);
Vue
<!-- AdwSwitchRow.vue — mount(AdwSwitchRow, container) from '@gjsify/gtk-host/vue' -->
<template>
<adw-preferences-group>
<adw-switch-row
title="Automatic updates"
subtitle="Download and install updates without asking"
:active="true"
/>
</adw-preferences-group>
</template>
TypeScript
// createRoot(container).render(<AdwSwitchRow />) — from '@gjsify/gtk-host/react'
const AdwSwitchRow = () => (
<adw-preferences-group>
<adw-switch-row
title="Automatic updates"
subtitle="Download and install updates without asking"
active
/>
</adw-preferences-group>
);
NativeScript
TypeScript
import { AdwSwitchRow } from '@gjsify/adwaita-nativescript';
const row = new AdwSwitchRow();
row.title = 'Automatic updates';
row.subtitle = 'Download and install updates without asking';
row.active = true;
XML
<adw:AdwPreferencesGroup
xmlns="http://schemas.nativescript.org/tns.xsd"
xmlns:adw="~/adwaita"
>
<adw:AdwSwitchRow
title="Automatic updates"
subtitle="Download and install updates without asking"
active="true"
/>
</adw:AdwPreferencesGroup>

Edit a short value in place. The title doubles as the label and placeholder for an inline text field, which suits a name, a hostname or a nickname. Set showApplyButton if the change should be committed explicitly rather than as the user types.

Adw.EntryRow
HTML
<adw-preferences-group>
<adw-entry-row title="Display name" text="Ada Lovelace"></adw-entry-row>
</adw-preferences-group>
<adw-entry-row> observes these in the browser port. Changing one re-renders the element. The second column is what the preview one tab to the left writes, read across every copy of the element in it. The other windows name their own properties.
Attribute In this preview
title Display name
text Ada Lovelace
editable not used
max-length not used
show-apply-button not used
activates-default not used
Native TypeScript
TypeScript
import Adw from 'gi://Adw?version=1';
const row = new Adw.EntryRow({
title: 'Display name',
text: 'Ada Lovelace',
showApplyButton: true,
});
Code
using Gtk 4.0;
using Adw 1;
Adw.PreferencesGroup {
Adw.EntryRow {
title: _("Display name");
text: "Ada Lovelace";
}
}
UI frameworks
TypeScript
// mount(() => <AdwEntryRow />, container) — from '@gjsify/gtk-host/solid'
const AdwEntryRow = () => (
<adw-preferences-group>
<adw-entry-row
title="Display name"
text="Ada Lovelace"
/>
</adw-preferences-group>
);
Vue
<!-- AdwEntryRow.vue — mount(AdwEntryRow, container) from '@gjsify/gtk-host/vue' -->
<template>
<adw-preferences-group>
<adw-entry-row
title="Display name"
text="Ada Lovelace"
/>
</adw-preferences-group>
</template>
TypeScript
// createRoot(container).render(<AdwEntryRow />) — from '@gjsify/gtk-host/react'
const AdwEntryRow = () => (
<adw-preferences-group>
<adw-entry-row
title="Display name"
text="Ada Lovelace"
/>
</adw-preferences-group>
);
NativeScript
TypeScript
import { AdwEntryRow } from '@gjsify/adwaita-nativescript';
const row = new AdwEntryRow();
row.title = 'Display name';
row.text = 'Ada Lovelace';
XML
<adw:AdwPreferencesGroup
xmlns="http://schemas.nativescript.org/tns.xsd"
xmlns:adw="~/adwaita"
>
<adw:AdwEntryRow
title="Display name"
text="Ada Lovelace"
/>
</adw:AdwPreferencesGroup>

The same row for secrets: it masks what you type and offers a peek toggle to reveal it. Use it anywhere a password or key is edited inline.

Adw.PasswordEntryRow
HTML
<adw-preferences-group>
<adw-password-entry-row title="Password" text="correct-horse-battery"></adw-password-entry-row>
</adw-preferences-group>
<adw-password-entry-row> observes these in the browser port. Changing one re-renders the element. The second column is what the preview one tab to the left writes, read across every copy of the element in it. The other windows name their own properties.
Attribute In this preview
title Password
text correct-horse-battery
editable not used
max-length not used
show-apply-button not used
activates-default not used
revealed not used
Native TypeScript
TypeScript
import Adw from 'gi://Adw?version=1';
const row = new Adw.PasswordEntryRow({
title: 'Password',
text: 'correct-horse-battery',
});
Code
using Gtk 4.0;
using Adw 1;
Adw.PreferencesGroup {
Adw.PasswordEntryRow {
title: _("Password");
text: "correct-horse-battery";
}
}
UI frameworks
TypeScript
// mount(() => <AdwPasswordEntryRow />, container) — from '@gjsify/gtk-host/solid'
const AdwPasswordEntryRow = () => (
<adw-preferences-group>
<adw-password-entry-row
title="Password"
text="correct-horse-battery"
/>
</adw-preferences-group>
);
Vue
<!-- AdwPasswordEntryRow.vue — mount(AdwPasswordEntryRow, container) from '@gjsify/gtk-host/vue' -->
<template>
<adw-preferences-group>
<adw-password-entry-row
title="Password"
text="correct-horse-battery"
/>
</adw-preferences-group>
</template>
TypeScript
// createRoot(container).render(<AdwPasswordEntryRow />) — from '@gjsify/gtk-host/react'
const AdwPasswordEntryRow = () => (
<adw-preferences-group>
<adw-password-entry-row
title="Password"
text="correct-horse-battery"
/>
</adw-preferences-group>
);
NativeScript
TypeScript
import { AdwPasswordEntryRow } from '@gjsify/adwaita-nativescript';
const row = new AdwPasswordEntryRow();
row.title = 'Password';
row.text = 'correct-horse-battery';
XML
<adw:AdwPreferencesGroup
xmlns="http://schemas.nativescript.org/tns.xsd"
xmlns:adw="~/adwaita"
>
<adw:AdwPasswordEntryRow
title="Password"
text="correct-horse-battery"
revealed="false"
/>
</adw:AdwPreferencesGroup>

Pick one option from a fixed list. The row shows an inline drop-down, and the selection is an index into the model you gave it, not the string itself.

Adw.ComboRow
HTML
<adw-preferences-group>
<adw-combo-row
title="Accent colour"
subtitle="Used to highlight selected items"
items='["Blue","Teal","Green","Orange","Purple"]'
selected="1"
></adw-combo-row>
</adw-preferences-group>
<adw-combo-row> observes these in the browser port. Changing one re-renders the element. The second column is what the preview one tab to the left writes, read across every copy of the element in it. The other windows name their own properties.
Attribute In this preview
title Accent colour
subtitle Used to highlight selected items
selected 1
Native TypeScript
TypeScript
import Adw from 'gi://Adw?version=1';
import Gtk from 'gi://Gtk?version=4.0';
const row = new Adw.ComboRow({
title: 'Accent colour',
subtitle: 'Used to highlight selected items',
model: new Gtk.StringList({ strings: ['Blue', 'Teal', 'Green', 'Orange', 'Purple'] }),
selected: 1,
});
Code
using Gtk 4.0;
using Adw 1;
Adw.PreferencesGroup {
Adw.ComboRow {
title: _("Accent colour");
subtitle: _("Used to highlight selected items");
selected: 1;
model: Gtk.StringList {
strings [_("Blue"), _("Teal"), _("Green"), _("Orange"), _("Purple")]
};
}
}
UI frameworks

No Solid, Vue or React snippet for Adw.ComboRow: its items are a Gio.ListModel; a row without them teaches the wrong thing.

Every snippet in this gallery was compiled and run before it was written down. Where a widget is built imperatively rather than declared — a Gio.MenuModel, a dialog opened with present(), a container with no child policy — there is nothing for the three dialects to differ about, so the reason is recorded here rather than the tab being quietly absent.

NativeScript
TypeScript
import { AdwComboRow } from '@gjsify/adwaita-nativescript';
const row = new AdwComboRow();
row.title = 'Accent colour';
row.subtitle = 'Used to highlight selected items';
row.options = ['Blue', 'Teal', 'Green', 'Orange', 'Purple'].map((s) => ({ label: s, value: s }));
row.selected = 1;

No NativeScript XML template for Adw.ComboRow: AdwComboRow.options is an array of choices; an XML attribute is a string.

NativeScript’s Builder reaches a widget through an attribute, which is always a string, and through a child, which lands only where the widget declares a slot for it. A property that is an array of options or a reference to another view fits through neither, so the TypeScript beside this window is where that widget is built.

Take a number within a range. The row carries an inline spin button with plus and minus steppers and optional decimal digits, which fits settings like a font size or a count.

Adw.SpinRow
HTML
<adw-preferences-group>
<adw-spin-row title="Font size" min="0" max="100" value="16" step="1"></adw-spin-row>
</adw-preferences-group>
<adw-spin-row> observes these in the browser port. Changing one re-renders the element. The second column is what the preview one tab to the left writes, read across every copy of the element in it. The other windows name their own properties.
Attribute In this preview
title Font size
subtitle not used
value 16
min 0
max 100
step 1
Native TypeScript
TypeScript
import Adw from 'gi://Adw?version=1';
import Gtk from 'gi://Gtk?version=4.0';
const row = new Adw.SpinRow({
title: 'Font size',
adjustment: new Gtk.Adjustment({ lower: 0, upper: 100, value: 16, stepIncrement: 1 }),
digits: 0,
});
Code
using Gtk 4.0;
using Adw 1;
Adw.PreferencesGroup {
Adw.SpinRow {
title: _("Font size");
adjustment: Gtk.Adjustment {
lower: 0;
upper: 100;
value: 16;
step-increment: 1;
};
}
}
UI frameworks

No Solid, Vue or React snippet for Adw.SpinRow: its range is a Gtk.Adjustment, a GObject that is not a widget.

Every snippet in this gallery was compiled and run before it was written down. Where a widget is built imperatively rather than declared — a Gio.MenuModel, a dialog opened with present(), a container with no child policy — there is nothing for the three dialects to differ about, so the reason is recorded here rather than the tab being quietly absent.

NativeScript
TypeScript
import { AdwSpinRow } from '@gjsify/adwaita-nativescript';
const row = new AdwSpinRow();
row.title = 'Font size';
row.min = 0;
row.max = 100;
row.value = 16;
row.step = 1;
XML
<adw:AdwPreferencesGroup
xmlns="http://schemas.nativescript.org/tns.xsd"
xmlns:adw="~/adwaita"
>
<adw:AdwSpinRow
title="Copies"
value="3"
min="1"
max="20"
step="1"
/>
</adw:AdwPreferencesGroup>

Tuck advanced or grouped settings out of the way. The row discloses its nested rows when expanded, and it can carry an enable switch that gates the whole section.

Adw.ExpanderRow
HTML
<adw-preferences-group>
<adw-expander-row title="Proxy settings" subtitle="Route traffic through a custom proxy" expanded>
<adw-entry-row title="Host" text="proxy.example.com"></adw-entry-row>
<adw-switch-row title="Use authentication"></adw-switch-row>
</adw-expander-row>
</adw-preferences-group>
<adw-expander-row> observes these in the browser port. Changing one re-renders the element. The second column is what the preview one tab to the left writes, read across every copy of the element in it. The other windows name their own properties.
Attribute In this preview
title Proxy settings
subtitle Route traffic through a custom proxy
expanded set
enable-expansion not used
show-enable-switch not used
Native TypeScript
TypeScript
import Adw from 'gi://Adw?version=1';
const row = new Adw.ExpanderRow({
title: 'Proxy settings',
subtitle: 'Route traffic through a custom proxy',
expanded: true,
});
row.add_row(new Adw.EntryRow({ title: 'Host', text: 'proxy.example.com' }));
row.add_row(new Adw.SwitchRow({ title: 'Use authentication', active: false }));
Code
using Gtk 4.0;
using Adw 1;
Adw.PreferencesGroup {
Adw.ExpanderRow {
title: _("Proxy settings");
subtitle: _("Route traffic through a custom proxy");
expanded: true;
Adw.EntryRow {
title: _("Host");
text: "proxy.example.com";
}
Adw.SwitchRow {
title: _("Use authentication");
}
}
}
UI frameworks
TypeScript
// mount(() => <AdwExpanderRow />, container) — from '@gjsify/gtk-host/solid'
const AdwExpanderRow = () => (
<adw-preferences-group>
<adw-expander-row
title="Proxy settings"
subtitle="Route traffic through a custom proxy"
expanded
>
<adw-entry-row
title="Host"
text="proxy.example.com"
/>
<adw-switch-row title="Use authentication" />
</adw-expander-row>
</adw-preferences-group>
);
Vue
<!-- AdwExpanderRow.vue — mount(AdwExpanderRow, container) from '@gjsify/gtk-host/vue' -->
<template>
<adw-preferences-group>
<adw-expander-row
title="Proxy settings"
subtitle="Route traffic through a custom proxy"
:expanded="true"
>
<adw-entry-row
title="Host"
text="proxy.example.com"
/>
<adw-switch-row title="Use authentication" />
</adw-expander-row>
</adw-preferences-group>
</template>
TypeScript
// createRoot(container).render(<AdwExpanderRow />) — from '@gjsify/gtk-host/react'
const AdwExpanderRow = () => (
<adw-preferences-group>
<adw-expander-row
title="Proxy settings"
subtitle="Route traffic through a custom proxy"
expanded
>
<adw-entry-row
title="Host"
text="proxy.example.com"
/>
<adw-switch-row title="Use authentication" />
</adw-expander-row>
</adw-preferences-group>
);
NativeScript
TypeScript
import { AdwExpanderRow, AdwEntryRow, AdwSwitchRow } from '@gjsify/adwaita-nativescript';
const row = new AdwExpanderRow();
row.title = 'Proxy settings';
row.subtitle = 'Route traffic through a custom proxy';
row.expanded = true;
const host = new AdwEntryRow();
host.title = 'Host';
host.text = 'proxy.example.com';
row.addRow(host);
const auth = new AdwSwitchRow();
auth.title = 'Use authentication';
row.addRow(auth);
XML
<adw:AdwPreferencesGroup
xmlns="http://schemas.nativescript.org/tns.xsd"
xmlns:adw="~/adwaita"
>
<adw:AdwExpanderRow
title="Advanced"
subtitle="Options most people leave alone"
expanded="true"
>
<adw:AdwSwitchRow
title="Developer mode"
active="false"
/>
<adw:AdwEntryRow
title="Endpoint"
text="https://example.invalid"
/>
</adw:AdwExpanderRow>
</adw:AdwPreferencesGroup>

Put an action at the end of a list, such as Add account or Remove. The whole row behaves like a button. It takes an optional start icon and the usual Adwaita style classes (.suggested-action, .destructive-action).

Adw.ButtonRow
HTML
<adw-preferences-group>
<adw-button-row title="Add account" start-icon-name="list-add" class="suggested-action"></adw-button-row>
</adw-preferences-group>
<adw-button-row> observes these in the browser port. Changing one re-renders the element. The second column is what the preview one tab to the left writes, read across every copy of the element in it. The other windows name their own properties.
Attribute In this preview
title Add account
start-icon-name list-add
end-icon-name not used
Native TypeScript
TypeScript
import Adw from 'gi://Adw?version=1';
const row = new Adw.ButtonRow({
title: 'Add account',
startIconName: 'list-add-symbolic',
});
row.add_css_class('suggested-action');
Code
using Gtk 4.0;
using Adw 1;
Adw.PreferencesGroup {
Adw.ButtonRow {
title: _("Add account");
start-icon-name: "list-add-symbolic";
styles ["suggested-action"]
}
}
UI frameworks
TypeScript
// mount(() => <AdwButtonRow />, container) — from '@gjsify/gtk-host/solid'
const AdwButtonRow = () => (
<adw-preferences-group>
<adw-button-row
title="Add account"
startIconName="list-add-symbolic"
cssClasses={['suggested-action']}
/>
</adw-preferences-group>
);
Vue
<!-- AdwButtonRow.vue — mount(AdwButtonRow, container) from '@gjsify/gtk-host/vue' -->
<template>
<adw-preferences-group>
<adw-button-row
title="Add account"
start-icon-name="list-add-symbolic"
:css-classes="['suggested-action']"
/>
</adw-preferences-group>
</template>
TypeScript
// createRoot(container).render(<AdwButtonRow />) — from '@gjsify/gtk-host/react'
const AdwButtonRow = () => (
<adw-preferences-group>
<adw-button-row
title="Add account"
startIconName="list-add-symbolic"
cssClasses={['suggested-action']}
/>
</adw-preferences-group>
);
NativeScript
TypeScript
import { AdwButtonRow } from '@gjsify/adwaita-nativescript';
import { listAddSymbolic } from '@gjsify/adwaita-icons/actions';
const row = new AdwButtonRow();
row.title = 'Add account';
row.startIconName = listAddSymbolic; // an Adwaita symbolic icon (SVG string)
row.className = 'adw-button-row suggested-action';
XML
<adw:AdwPreferencesGroup
xmlns="http://schemas.nativescript.org/tns.xsd"
xmlns:adw="~/adwaita"
>
<adw:AdwButtonRow title="Add account" />
</adw:AdwPreferencesGroup>
  • Buttons: button content, split buttons and toggle groups.
  • Gtk Controls: the standalone entry and drop down that the entry row and combo row are twins of.
  • Gtk Buttons: the style classes these rows reuse.
  • Layout: the Clamp that keeps a boxed list at a readable width.
  • Feedback: the preferences dialog these groups go into.
  • Adwaita Storybook: the same widgets in a live component browser you can poke at.