Skip to content

Boxed Lists

A boxed list is Adwaita’s core pattern for settings and detail screens: a set of related rows gathered into a single rounded card. The card is a preferences group; each row is a small, self-contained control — a toggle, a text field, a drop-down, a button.

Every widget below is described independently of any one toolkit, then shown three ways. Native GJS (real Libadwaita through @girs/adw-1) is the primary implementation; the Web (@gjsify/adwaita-web) and NativeScript (@gjsify/adwaita-nativescript) ports mirror it. The preview is the real Web component — no screenshot — so it follows the light/dark toggle just like a native window would.

The container for a boxed list. It renders its rows as one rounded card and can carry a title, a description, and a header-suffix widget (a button or switch pinned to the trailing edge of the header). Groups stack vertically to build a full preferences page.

Adw.PreferencesGroup
TypeScript
import Adw from '@girs/adw-1';
import Gtk from '@girs/gtk-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")]
};
}
}
HTML
<!-- import '@gjsify/adwaita-web' once to register the elements -->
<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" active></adw-switch-row>
</adw-preferences-group>
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);

The most general 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). Marking it activatable makes the whole row respond to a click — typically to open a detail page.

Adw.ActionRow
TypeScript
import Adw from '@girs/adw-1';
import Gtk from '@girs/gtk-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";
}
}
}
HTML
<adw-action-row title="Wi-Fi" subtitle="Connected to Highgarden 5GHz" activatable>
<span slot="prefix" class="adw-icon adw-icon--network-wireless"></span>
<adw-button slot="suffix" icon="go-next" flat></adw-button>
</adw-action-row>
TypeScript
import { AdwActionRow, AdwIcon } from '@gjsify/adwaita-nativescript';
const row = new AdwActionRow();
row.title = 'Wi-Fi';
row.subtitle = 'Connected to Highgarden 5GHz';
const icon = new AdwIcon();
icon.icon = networkWirelessSymbolic; // an Adwaita symbolic icon (SVG string)
row.setPrefix(icon);
const chevron = new AdwIcon();
chevron.icon = goNextSymbolic;
row.setSuffix(chevron);

An action row with a trailing switch that toggles a single boolean setting — the boxed-list equivalent of a labelled on/off control.

Adw.SwitchRow
TypeScript
import Adw from '@girs/adw-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;
}
}
HTML
<adw-switch-row
title="Automatic updates"
subtitle="Download and install updates without asking"
active
></adw-switch-row>
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;

A row whose title doubles as the label and placeholder for an inline text field. Ideal for short, editable values — a name, a hostname, a nickname. It can show an apply button that commits the change.

Adw.EntryRow
TypeScript
import Adw from '@girs/adw-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";
}
}
HTML
<adw-entry-row title="Display name" text="Ada Lovelace"></adw-entry-row>
TypeScript
import { AdwEntryRow } from '@gjsify/adwaita-nativescript';
const row = new AdwEntryRow();
row.title = 'Display name';
row.text = 'Ada Lovelace';

An entry row that masks its contents and offers a peek toggle to reveal them. Use it wherever a secret is edited inline in a boxed list.

Adw.PasswordEntryRow
TypeScript
import Adw from '@girs/adw-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";
}
}
HTML
<adw-password-entry-row title="Password" text="correct-horse-battery"></adw-password-entry-row>
TypeScript
import { AdwPasswordEntryRow } from '@gjsify/adwaita-nativescript';
const row = new AdwPasswordEntryRow();
row.title = 'Password';
row.text = 'correct-horse-battery';

A row with an inline drop-down for choosing one option from a fixed list. The selection is stored as an index into the model.

Adw.ComboRow
TypeScript
import Adw from '@girs/adw-1';
import Gtk from '@girs/gtk-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")]
};
}
}
HTML
<adw-combo-row
title="Accent colour"
subtitle="Used to highlight selected items"
items='["Blue","Teal","Green","Orange","Purple"]'
selected="1"
></adw-combo-row>
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.selectedIndex = 1;

A row with an inline spin button over a numeric range — a value with ± steppers and optional decimal digits, for settings like a font size or a count.

Adw.SpinRow
TypeScript
import Adw from '@girs/adw-1';
import Gtk from '@girs/gtk-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;
};
}
}
HTML
<adw-spin-row title="Font size" min="0" max="100" value="16" step="1"></adw-spin-row>
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;

A row that discloses nested rows when expanded — a lightweight way to tuck away advanced or grouped settings. It can carry an enable switch that gates the whole section.

Adw.ExpanderRow
TypeScript
import Adw from '@girs/adw-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");
}
}
}
HTML
<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>
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);

A full-width row that behaves like a button — for a boxed-list action such as Add account or Remove. It takes an optional start icon and an Adwaita style class (.suggested-action, .destructive-action).

Adw.ButtonRow
TypeScript
import Adw from '@girs/adw-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"]
}
}
HTML
<adw-button-row
title="Add account"
start-icon-name="list-add"
class="suggested-action"
></adw-button-row>
TypeScript
import { AdwButtonRow } from '@gjsify/adwaita-nativescript';
const row = new AdwButtonRow();
row.title = 'Add account';
row.startIcon = listAddSymbolic; // an Adwaita symbolic icon (SVG string)
row.className = 'adw-button-row suggested-action';
  • Buttons — standalone buttons and the style classes reused here.
  • Layout — the Clamp that keeps a boxed list at a readable width.
  • Adwaita Storybook — the same widgets in a live, interactive component browser.