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.
What the preview does not show
The previews run the browser port, so behaviour Libadwaita drives natively (an entry’s apply button, a spin button’s repeat, the press feedback on a row) can be simplified here.
Preferences Group
Section titled “Preferences Group”The group 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 for a full preferences page.
using Gtk 4.0;using Adw 1;
Adw.PreferencesGroup { title: _("Account"); description: _("Manage how this device signs in and syncs.");
header-suffix: Gtk.Button sign_out { label: _("Sign out"); valign: center;
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");
model: Gtk.StringList { strings [ _("Europe"), _("Americas"), _("Asia"), _("Oceania"), ] };
selected: 0; }}import { build } from './preferences-group.blp';
const { sign_out } = build();sign_out.connect('clicked', () => console.log('Sign out'));<adw-preferences-group title="Account" description="Manage how this device signs in and syncs."> <gtk-button id="sign_out" label="Sign out" valign="center" class="flat" slot="header-suffix" ></gtk-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" selected="0"> <gtk-string-list strings='["Europe","Americas","Asia","Oceania"]' slot="model" ></gtk-string-list> </adw-combo-row></adw-preferences-group><script type="module"> import '@gjsify/adwaita-web';
const signOut = document.querySelector('#sign_out'); signOut.addEventListener('click', () => console.log('Sign out'));</script>import { mountSharedTree } from '@gjsify/adwaita-web';import tree from './preferences-group.blp?shared-tree';
mountSharedTree(tree);
const signOut = document.querySelector('#sign_out');signOut.addEventListener('click', () => console.log('Sign out'));<adw:PreferencesGroup xmlns="http://schemas.nativescript.org/tns.xsd" xmlns:adw="~/adw" xmlns:gtk="~/gtk" title="Account" description="Manage how this device signs in and syncs."> <adw:PreferencesGroup.header-suffix> <gtk:Button id="sign_out" label="Sign out" valign="center" styleClasses="flat" /> </adw:PreferencesGroup.header-suffix> <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"> <adw:ComboRow.model> <gtk:StringList strings='["Europe","Americas","Asia","Oceania"]' /> </adw:ComboRow.model> </adw:ComboRow></adw:PreferencesGroup>import { type Adw, type Gtk } from '@gjsify/adwaita-nativescript';import { Builder } from '@nativescript/core';
const group = Builder.load({ path: '~/views', name: 'preferences-group' }) as Adw.PreferencesGroup;const signOut = group.getViewById<Gtk.Button>('sign_out')!;signOut.connect('clicked', () => console.log('Sign out'));import { type Adw, type Gtk } from '@gjsify/adwaita-nativescript';import { build } from '@gjsify/adwaita-nativescript/builder';import tree from './preferences-group.blp?shared-tree';
const group = build(tree) as Adw.PreferencesGroup;const signOut = group.getViewById<Gtk.Button>('sign_out')!;signOut.connect('clicked', () => console.log('Sign out'));// 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>);<!-- 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>// 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>);Preferences Row
Section titled “Preferences Row”The base every row in a boxed list grows from: a list row with a title and nothing more. The title is the text the preferences dialog searches, so give a row one even when you draw the rest yourself. It takes Pango markup unless use-markup is off, an underscore marks a mnemonic with use-underline, and title-selectable lets the user copy it. The action, switch and entry rows all add their own controls on top of this one.
using Gtk 4.0;using Adw 1;
Adw.PreferencesGroup { Adw.PreferencesRow { title: _("A plain preferences row"); use-markup: true; }}import Adw from 'gi://Adw?version=1';
const row = new Adw.PreferencesRow({ title: 'A plain preferences row', useMarkup: true });
const group = new Adw.PreferencesGroup();group.add(row);<adw-preferences-group> <!-- use-markup: Whether to use Pango markup for the title label. --> <adw-preferences-row title="A plain preferences row" use-markup></adw-preferences-row></adw-preferences-group>// mount(() => <AdwPreferencesRow />, container) — from '@gjsify/gtk-host/solid'const AdwPreferencesRow = () => ( <adw-preferences-group> <adw-preferences-row title="A plain preferences row" useMarkup /> </adw-preferences-group>);<!-- AdwPreferencesRow.vue — mount(AdwPreferencesRow, container) from '@gjsify/gtk-host/vue' --><template> <adw-preferences-group> <adw-preferences-row title="A plain preferences row" :use-markup="true" /> </adw-preferences-group></template>// createRoot(container).render(<AdwPreferencesRow />) — from '@gjsify/gtk-host/react'const AdwPreferencesRow = () => ( <adw-preferences-group> <adw-preferences-row title="A plain preferences row" useMarkup /> </adw-preferences-group>);Action Row
Section titled “Action Row”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.
using Gtk 4.0;using Adw 1;
Adw.PreferencesGroup { Adw.ActionRow row { 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"; } }}import { build } from './action-row.blp';
const { row } = build();row.connect('activated', () => console.log('Open Wi-Fi settings'));<adw-preferences-group> <adw-action-row id="row" title="Wi-Fi" subtitle="Connected to Highgarden 5GHz" activatable > <gtk-image icon-name="network-wireless-symbolic" slot="prefix"></gtk-image> <gtk-image icon-name="go-next-symbolic" slot="suffix"></gtk-image> </adw-action-row></adw-preferences-group><script type="module"> import '@gjsify/adwaita-web';
const row = document.querySelector('#row'); row.addEventListener('activated', () => console.log('Open Wi-Fi settings'));</script>import { mountSharedTree } from '@gjsify/adwaita-web';import tree from './action-row.blp?shared-tree';
mountSharedTree(tree);
const row = document.querySelector('#row');row.addEventListener('activated', () => console.log('Open Wi-Fi settings'));<adw:PreferencesGroup xmlns="http://schemas.nativescript.org/tns.xsd" xmlns:adw="~/adw" xmlns:gtk="~/gtk"> <adw:ActionRow id="row" title="Wi-Fi" subtitle="Connected to Highgarden 5GHz" activatable="true" > <adw:ActionRow.prefix> <gtk:Image iconName="network-wireless-symbolic" /> </adw:ActionRow.prefix> <adw:ActionRow.suffix> <gtk:Image iconName="go-next-symbolic" /> </adw:ActionRow.suffix> </adw:ActionRow></adw:PreferencesGroup>import { type Adw } from '@gjsify/adwaita-nativescript';import { Builder } from '@nativescript/core';
const group = Builder.load({ path: '~/views', name: 'action-row' }) as Adw.PreferencesGroup;const row = group.getViewById<Adw.ActionRow>('row')!;row.connect('activated', () => console.log('Open Wi-Fi settings'));import { type Adw } from '@gjsify/adwaita-nativescript';import { build } from '@gjsify/adwaita-nativescript/builder';import tree from './action-row.blp?shared-tree';
const group = build(tree) as Adw.PreferencesGroup;const row = group.getViewById<Adw.ActionRow>('row')!;row.connect('activated', () => console.log('Open Wi-Fi settings'));// 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>);<!-- 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>// 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>);Switch Row
Section titled “Switch Row”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.
using Gtk 4.0;using Adw 1;
Adw.PreferencesGroup { Adw.SwitchRow row { title: _("Automatic updates"); subtitle: _("Download and install updates without asking"); active: true; }}import { build } from './switch-row.blp';
const { row } = build();row.connect('notify::active', () => console.log('Automatic updates:', row.active));<adw-preferences-group> <adw-switch-row id="row" title="Automatic updates" subtitle="Download and install updates without asking" active ></adw-switch-row></adw-preferences-group><script type="module"> import '@gjsify/adwaita-web';
const row = document.querySelector('#row'); row.addEventListener('notify::active', () => console.log('Automatic updates:', row.hasAttribute('active')));</script>import { mountSharedTree } from '@gjsify/adwaita-web';import tree from './switch-row.blp?shared-tree';
mountSharedTree(tree);
const row = document.querySelector('#row');row.addEventListener('notify::active', () => console.log('Automatic updates:', row.hasAttribute('active')));<adw:PreferencesGroup xmlns="http://schemas.nativescript.org/tns.xsd" xmlns:adw="~/adw"> <adw:SwitchRow id="row" title="Automatic updates" subtitle="Download and install updates without asking" active="true" /></adw:PreferencesGroup>import { type Adw } from '@gjsify/adwaita-nativescript';import { Builder } from '@nativescript/core';
const group = Builder.load({ path: '~/views', name: 'switch-row' }) as Adw.PreferencesGroup;const row = group.getViewById<Adw.SwitchRow>('row')!;row.connect('notify::active', () => console.log('Automatic updates:', row.active));import { type Adw } from '@gjsify/adwaita-nativescript';import { build } from '@gjsify/adwaita-nativescript/builder';import tree from './switch-row.blp?shared-tree';
const group = build(tree) as Adw.PreferencesGroup;const row = group.getViewById<Adw.SwitchRow>('row')!;row.connect('notify::active', () => console.log('Automatic updates:', row.active));// 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>);<!-- 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>// 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>);Entry Row
Section titled “Entry Row”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.
using Gtk 4.0;using Adw 1;
Adw.PreferencesGroup { Adw.EntryRow row { title: _("Display name"); text: "Ada Lovelace"; }}import { build } from './entry-row.blp';
const { row } = build();row.connect('notify::text', () => console.log('Display name:', row.text));<adw-preferences-group> <adw-entry-row id="row" title="Display name" text="Ada Lovelace" ></adw-entry-row></adw-preferences-group><script type="module"> import '@gjsify/adwaita-web';
const row = document.querySelector('#row'); row.addEventListener('notify::text', () => console.log('Display name:', row.getAttribute('text')));</script>import { mountSharedTree } from '@gjsify/adwaita-web';import tree from './entry-row.blp?shared-tree';
mountSharedTree(tree);
const row = document.querySelector('#row');row.addEventListener('notify::text', () => console.log('Display name:', row.getAttribute('text')));<adw:PreferencesGroup xmlns="http://schemas.nativescript.org/tns.xsd" xmlns:adw="~/adw"> <adw:EntryRow id="row" title="Display name" text="Ada Lovelace" /></adw:PreferencesGroup>import { type Adw } from '@gjsify/adwaita-nativescript';import { Builder } from '@nativescript/core';
const group = Builder.load({ path: '~/views', name: 'entry-row' }) as Adw.PreferencesGroup;const row = group.getViewById<Adw.EntryRow>('row')!;row.connect('notify::text', () => console.log('Display name:', row.text));import { type Adw } from '@gjsify/adwaita-nativescript';import { build } from '@gjsify/adwaita-nativescript/builder';import tree from './entry-row.blp?shared-tree';
const group = build(tree) as Adw.PreferencesGroup;const row = group.getViewById<Adw.EntryRow>('row')!;row.connect('notify::text', () => console.log('Display name:', row.text));// 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>);<!-- 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>// 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>);Password Entry Row
Section titled “Password Entry Row”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.
using Gtk 4.0;using Adw 1;
Adw.PreferencesGroup { Adw.PasswordEntryRow row { title: _("Password"); text: "correct-horse-battery"; }}import { build } from './password-entry-row.blp';
const { row } = build();row.connect('notify::text', () => console.log('Password length:', row.text.length));<adw-preferences-group> <adw-password-entry-row id="row" title="Password" text="correct-horse-battery" ></adw-password-entry-row></adw-preferences-group><script type="module"> import '@gjsify/adwaita-web';
const row = document.querySelector('#row'); row.addEventListener('notify::text', () => console.log('Password length:', row.getAttribute('text')?.length));</script>import { mountSharedTree } from '@gjsify/adwaita-web';import tree from './password-entry-row.blp?shared-tree';
mountSharedTree(tree);
const row = document.querySelector('#row');row.addEventListener('notify::text', () => console.log('Password length:', row.getAttribute('text')?.length));<adw:PreferencesGroup xmlns="http://schemas.nativescript.org/tns.xsd" xmlns:adw="~/adw"> <adw:PasswordEntryRow id="row" title="Password" text="correct-horse-battery" /></adw:PreferencesGroup>import { type Adw } from '@gjsify/adwaita-nativescript';import { Builder } from '@nativescript/core';
const group = Builder.load({ path: '~/views', name: 'password-entry-row' }) as Adw.PreferencesGroup;const row = group.getViewById<Adw.PasswordEntryRow>('row')!;row.connect('notify::text', () => console.log('Password length:', row.text.length));import { type Adw } from '@gjsify/adwaita-nativescript';import { build } from '@gjsify/adwaita-nativescript/builder';import tree from './password-entry-row.blp?shared-tree';
const group = build(tree) as Adw.PreferencesGroup;const row = group.getViewById<Adw.PasswordEntryRow>('row')!;row.connect('notify::text', () => console.log('Password length:', row.text.length));// 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>);<!-- 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>// 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>);Combo Row
Section titled “Combo Row”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.
using Gtk 4.0;using Adw 1;
Adw.PreferencesGroup { Adw.ComboRow row { title: _("Accent colour"); subtitle: _("Used to highlight selected items");
model: Gtk.StringList { strings [ _("Blue"), _("Teal"), _("Green"), _("Orange"), _("Purple"), ] };
selected: 1; }}import { build } from './combo-row.blp';
const { row } = build();row.connect('notify::selected', () => console.log(`Accent ${row.selected}`));<adw-preferences-group> <adw-combo-row id="row" title="Accent colour" subtitle="Used to highlight selected items" selected="1" > <gtk-string-list strings='["Blue","Teal","Green","Orange","Purple"]' slot="model" ></gtk-string-list> </adw-combo-row></adw-preferences-group><script type="module"> import '@gjsify/adwaita-web';
const row = document.querySelector('#row'); row.addEventListener('notify::selected', () => console.log(`Accent ${row.selected}`));</script>import { mountSharedTree } from '@gjsify/adwaita-web';import tree from './combo-row.blp?shared-tree';
mountSharedTree(tree);
const row = document.querySelector('#row');row.addEventListener('notify::selected', () => console.log(`Accent ${row.selected}`));<adw:PreferencesGroup xmlns="http://schemas.nativescript.org/tns.xsd" xmlns:adw="~/adw" xmlns:gtk="~/gtk"> <adw:ComboRow id="row" title="Accent colour" subtitle="Used to highlight selected items" selected="1" > <adw:ComboRow.model> <gtk:StringList strings='["Blue","Teal","Green","Orange","Purple"]' /> </adw:ComboRow.model> </adw:ComboRow></adw:PreferencesGroup>import { type Adw } from '@gjsify/adwaita-nativescript';import { Builder } from '@nativescript/core';
const group = Builder.load({ path: '~/views', name: 'combo-row' }) as Adw.PreferencesGroup;const row = group.getViewById<Adw.ComboRow>('row')!;row.connect('notify::selected', () => console.log(`Accent ${row.selected}`));import { type Adw } from '@gjsify/adwaita-nativescript';import { build } from '@gjsify/adwaita-nativescript/builder';import tree from './combo-row.blp?shared-tree';
const group = build(tree) as Adw.PreferencesGroup;const row = group.getViewById<Adw.ComboRow>('row')!;row.connect('notify::selected', () => console.log(`Accent ${row.selected}`));// mount(() => <AdwComboRow />, container) — from '@gjsify/gtk-host/solid'const AdwComboRow = () => ( <adw-preferences-group> <adw-combo-row title="Accent colour" subtitle="Used to highlight selected items" model={['Blue', 'Teal', 'Green', 'Orange', 'Purple']} selected={1} /> </adw-preferences-group>);<!-- AdwComboRow.vue — mount(AdwComboRow, container) from '@gjsify/gtk-host/vue' --><template> <adw-preferences-group> <adw-combo-row title="Accent colour" subtitle="Used to highlight selected items" :model="['Blue', 'Teal', 'Green', 'Orange', 'Purple']" :selected="1" /> </adw-preferences-group></template>// createRoot(container).render(<AdwComboRow />) — from '@gjsify/gtk-host/react'const AdwComboRow = () => ( <adw-preferences-group> <adw-combo-row title="Accent colour" subtitle="Used to highlight selected items" model={['Blue', 'Teal', 'Green', 'Orange', 'Purple']} selected={1} /> </adw-preferences-group>);The model stays live: assign a new one and the row follows — the visible list, the inline value and the chevron, which the row hides while there is nothing to choose between.
const row = document.querySelector('adw-combo-row');
row.model = ['Blue', 'Teal'];row.selectedValue = 'Teal'; // pick by value; `row.selected` picks by indexrow.selectedItem; // → { value: 'Teal', label: 'Teal' }
row.model = [...row.model, { value: 'g', label: 'Green' }];What the model property accepts
The list is the model property, a Gtk.StringList in the Blueprint above. In
code it can also be an array of plain strings, or of { value, label } objects
when the value you store differs from the text you show — { label: 'Blue' } on
its own is addressed by 'Blue'. Write model before selected in Blueprint:
GtkBuilder sets properties in file order, and setting a model resets the selection,
so a selected written first ends up on the first item.
That last line above adds one option and leaves the two already on screen alone, so
a list that grows does not flicker or lose the reader’s place. Reading row.model
hands you a copy, so you can push, filter or rename an item and nothing on screen
moves until you assign it back.
The same array is what <gtk-drop-down> takes,
under the same model name — and so do Adw.ComboRow on NativeScript and the
<AdwComboRow model={…}> prop in React Native, so one model moves between the
surfaces without being rewritten.
Gtk.StringList is the other spelling of that same array, and the code windows
above use it because it is what a GJS author writes. On GJS it is the real
GtkStringList; on the web and NativeScript ports it is an Array subclass, so
model = ['Blue', 'Teal'] and
model = new Gtk.StringList({ strings: ['Blue', 'Teal'] }) are the same write and
either one reads back the same list.
Which widgets take a `model`
model is what this row and the drop-down take, and only they. The widgets whose
contents are child widgets — sidebar, tab view, toggle group, view stack,
carousel — have no such property, here or in Libadwaita: their items are added one
at a time. Keep using what each one already gives you — <adw-sidebar>’s
sections, <adw-tab-view>’s appendPage(), or plain child elements in markup
for the toggle group, the view stack and the carousel.
Spin Row
Section titled “Spin Row”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.
using Gtk 4.0;using Adw 1;
Adw.PreferencesGroup { Adw.SpinRow row { title: _("Font size");
adjustment: Gtk.Adjustment { lower: 0; upper: 100; value: 16; step-increment: 1; }; }}import { build } from './spin-row.blp';
const { row } = build();row.connect('notify::value', () => console.log(`Font size ${row.value}`));<adw-preferences-group> <adw-spin-row id="row" title="Font size"> <gtk-adjustment lower="0" upper="100" value="16" step-increment="1" slot="adjustment" ></gtk-adjustment> </adw-spin-row></adw-preferences-group><script type="module"> import '@gjsify/adwaita-web';
const row = document.querySelector('#row'); row.addEventListener('notify::value', () => console.log(`Font size ${row.value}`));</script>import { mountSharedTree } from '@gjsify/adwaita-web';import tree from './spin-row.blp?shared-tree';
mountSharedTree(tree);
const row = document.querySelector('#row');row.addEventListener('notify::value', () => console.log(`Font size ${row.value}`));<adw:PreferencesGroup xmlns="http://schemas.nativescript.org/tns.xsd" xmlns:adw="~/adw" xmlns:gtk="~/gtk"> <adw:SpinRow id="row" title="Font size"> <adw:SpinRow.adjustment> <gtk:Adjustment lower="0" upper="100" value="16" stepIncrement="1" /> </adw:SpinRow.adjustment> </adw:SpinRow></adw:PreferencesGroup>import { type Adw } from '@gjsify/adwaita-nativescript';import { Builder } from '@nativescript/core';
const group = Builder.load({ path: '~/views', name: 'spin-row' }) as Adw.PreferencesGroup;const row = group.getViewById<Adw.SpinRow>('row')!;row.connect('notify::value', () => console.log(`Font size ${row.value}`));import { type Adw } from '@gjsify/adwaita-nativescript';import { build } from '@gjsify/adwaita-nativescript/builder';import tree from './spin-row.blp?shared-tree';
const group = build(tree) as Adw.PreferencesGroup;const row = group.getViewById<Adw.SpinRow>('row')!;row.connect('notify::value', () => console.log(`Font size ${row.value}`));// mount(() => <AdwSpinRow />, container) — from '@gjsify/gtk-host/solid'const AdwSpinRow = () => ( <adw-preferences-group> <adw-spin-row title="Font size" adjustment={{ lower: 0, upper: 100, value: 16, stepIncrement: 1 }} /> </adw-preferences-group>);<!-- AdwSpinRow.vue — mount(AdwSpinRow, container) from '@gjsify/gtk-host/vue' --><template> <adw-preferences-group> <adw-spin-row title="Font size" :adjustment="{ lower: 0, upper: 100, value: 16, stepIncrement: 1 }" /> </adw-preferences-group></template>// createRoot(container).render(<AdwSpinRow />) — from '@gjsify/gtk-host/react'const AdwSpinRow = () => ( <adw-preferences-group> <adw-spin-row title="Font size" adjustment={{ lower: 0, upper: 100, value: 16, stepIncrement: 1 }} /> </adw-preferences-group>);Expander Row
Section titled “Expander Row”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.
using Gtk 4.0;using Adw 1;
Adw.PreferencesGroup { Adw.ExpanderRow row { title: _("Proxy settings"); subtitle: _("Route traffic through a custom proxy"); expanded: true;
[prefix] Gtk.Button { label: _("Test"); }
Adw.EntryRow host_row { title: _("Host"); text: "proxy.example.com"; }
Adw.SwitchRow { title: _("Use authentication"); } }}import { build } from './expander-row.blp';
const { row, host_row } = build();row.connect('notify::expanded', () => host_row.grab_focus());<adw-preferences-group> <adw-expander-row id="row" title="Proxy settings" subtitle="Route traffic through a custom proxy" expanded > <gtk-button label="Test" slot="prefix"></gtk-button> <adw-entry-row id="host_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><script type="module"> import '@gjsify/adwaita-web';
const row = document.querySelector('#row'); const host = document.querySelector('#host_row'); row.addEventListener('notify::expanded', () => host.focus());</script>import { mountSharedTree } from '@gjsify/adwaita-web';import tree from './expander-row.blp?shared-tree';
mountSharedTree(tree);
const row = document.querySelector('#row');const host = document.querySelector('#host_row');row.addEventListener('notify::expanded', () => host.focus());<adw:PreferencesGroup xmlns="http://schemas.nativescript.org/tns.xsd" xmlns:adw="~/adw" xmlns:gtk="~/gtk"> <adw:ExpanderRow id="row" title="Proxy settings" subtitle="Route traffic through a custom proxy" expanded="true" > <adw:ExpanderRow.prefix> <gtk:Button label="Test" /> </adw:ExpanderRow.prefix> <adw:EntryRow id="host_row" title="Host" text="proxy.example.com" /> <adw:SwitchRow title="Use authentication" /> </adw:ExpanderRow></adw:PreferencesGroup>import { type Adw } from '@gjsify/adwaita-nativescript';import { Builder } from '@nativescript/core';
const group = Builder.load({ path: '~/views', name: 'expander-row' }) as Adw.PreferencesGroup;const row = group.getViewById<Adw.ExpanderRow>('row')!;const host = row.getViewById<Adw.EntryRow>('host_row')!;row.connect('notify::expanded', () => host.focus());import { type Adw } from '@gjsify/adwaita-nativescript';import { build } from '@gjsify/adwaita-nativescript/builder';import tree from './expander-row.blp?shared-tree';
const group = build(tree) as Adw.PreferencesGroup;const row = group.getViewById<Adw.ExpanderRow>('row')!;const host = row.getViewById<Adw.EntryRow>('host_row')!;row.connect('notify::expanded', () => host.focus());// 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 > <gtk-button slot="prefix" label="Test" /> <adw-entry-row title="Host" text="proxy.example.com" /> <adw-switch-row title="Use authentication" /> </adw-expander-row> </adw-preferences-group>);<!-- 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" > <gtk-button slot="prefix" label="Test" /> <adw-entry-row title="Host" text="proxy.example.com" /> <adw-switch-row title="Use authentication" /> </adw-expander-row> </adw-preferences-group></template>// 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 > <gtk-button slot="prefix" label="Test" /> <adw-entry-row title="Host" text="proxy.example.com" /> <adw-switch-row title="Use authentication" /> </adw-expander-row> </adw-preferences-group>);Button Row
Section titled “Button Row”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).
using Gtk 4.0;using Adw 1;
Adw.PreferencesGroup { Adw.ButtonRow row { title: _("Add account"); start-icon-name: "list-add-symbolic";
styles ["suggested-action"] }}import { build } from './button-row.blp';
const { row } = build();row.connect('activated', () => console.log('Add an account'));<adw-preferences-group> <adw-button-row id="row" title="Add account" start-icon-name="list-add-symbolic" class="suggested-action" ></adw-button-row></adw-preferences-group><script type="module"> import '@gjsify/adwaita-web';
const row = document.querySelector('#row'); row.addEventListener('activated', () => console.log('Add an account'));</script>import { mountSharedTree } from '@gjsify/adwaita-web';import tree from './button-row.blp?shared-tree';
mountSharedTree(tree);
const row = document.querySelector('#row');row.addEventListener('activated', () => console.log('Add an account'));<adw:PreferencesGroup xmlns="http://schemas.nativescript.org/tns.xsd" xmlns:adw="~/adw"> <adw:ButtonRow id="row" title="Add account" startIconName="list-add-symbolic" styleClasses="suggested-action" /></adw:PreferencesGroup>import { type Adw } from '@gjsify/adwaita-nativescript';import { Builder } from '@nativescript/core';
const group = Builder.load({ path: '~/views', name: 'button-row' }) as Adw.PreferencesGroup;const row = group.getViewById<Adw.ButtonRow>('row')!;row.connect('activated', () => console.log('Add an account'));import { type Adw } from '@gjsify/adwaita-nativescript';import { build } from '@gjsify/adwaita-nativescript/builder';import tree from './button-row.blp?shared-tree';
const group = build(tree) as Adw.PreferencesGroup;const row = group.getViewById<Adw.ButtonRow>('row')!;row.connect('activated', () => console.log('Add an account'));// 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>);<!-- 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>// 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>);Related
Section titled “Related”- 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
Clampthat keeps a boxed list at a readable width. - Feedback: the preferences dialog these groups go into.
- Adwaita Storybook: the same widgets in a component browser you can poke at.