MCPInstall

designing-gnome-ui

Use for every user-visible change in a GNOME app, new or existing, whether or not the request uses design vocabulary. Trigger on the repo rather than the wording — if it depends on gtk4/libadwaita (or is a GNOME-targeted Qt/PySide6 app), anything a user can see or interact with goes through this skill, including requests phrased purely as symptoms ("can I right-click to delete", "the window opens too small", "reordering doesn't work"). Covers choosing widgets, icons, dialogs, menus, sidebars, navigation, and empty states; interaction bugs in context menus, drag-and-drop reordering, window sizing, layout, duplicate affordances, and controls missing or inert at launch; and HIG review. Complements developing-gtk-apps, which owns architecture, threading, language syntax, and build/test plumbing.

Installs
100
Last 24h
—
Trending rank
—
Security
Not audited

Install

Works with every agent the skills CLI supports.

npx skills add https://github.com/mhagrelius/dotfiles --skill designing-gnome-ui
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads designing-gnome-ui automatically when relevant.

  3. 03

    Review the result

    The agent follows the SKILL.md steps, scripts and references bundled with the skill.

SKILL.md

The instructions your agent reads when the skill is triggered.

Designing GNOME UI

Design GNOME UIs that are HIG-compliant, polished, and user-centered.

Core principle: No UI code without design decisions. Pattern selection happens before implementation.

Companion skill: For app architecture (lifecycle, threading, GSettings, actions, list-model/factory code, packaging), use developing-gtk-apps. Snippets in this skill are Python (PyGObject) and illustrate which widget and how it fits together; for Vala or Rust syntax, use that skill's language branch files.

Subagents: a subagent given UI work loads no skills on its own — its prompt must tell it to invoke designing-gnome-ui (and developing-gtk-apps for plumbing).

What's Current (libadwaita 1.9, GTK 4.22)

Training data reaches for APIs that are now deprecated. Write the current column, every time:

Deprecated (when)Current (since)
AdwPreferencesWindow (1.6)AdwPreferencesDialog (1.5)
AdwMessageDialog (1.6), GtkMessageDialog (4.10)AdwAlertDialog (1.5)
AdwAboutWindow (1.6)AdwAboutDialog (1.5)
AdwLeaflet, AdwFlap, AdwSqueezer, AdwViewSwitcherTitle (all 1.4)AdwBreakpoint + AdwNavigationSplitView/AdwNavigationView/AdwOverlaySplitView, AdwToolbarView (all 1.4)
GtkShortcutsWindow (4.18)AdwShortcutsDialog (1.8)
GtkFileChooserDialog/Native (4.10)GtkFileDialog (4.10, async)
GtkColorChooserWidget/Button (4.10)GtkColorDialog + GtkColorDialogButton (4.10)
GtkVolumeButton (4.10)GtkScaleButton or GtkScale
GtkSpinner (in Adw apps)AdwSpinner (1.6) — works with animations disabled
.dim-label CSS class.dimmed
@accent_color named colors, @define-colorvar(--accent-color) CSS variables

Why the *Window → *Dialog shift: AdwDialog (1.5) presents adaptively — a centered dialog on desktop, a bottom sheet on narrow/mobile screens — and attaches with dialog.present(parent) instead of transient_for. Every window-based dialog type was retired in its favor; when you meet a new Adw*Window/Adw*Dialog pair, the *Dialog one is current.

Widgets newer than training data (verify the API, don't guess it):

NeedWidget (since)
Exclusive toggles (view mode)AdwToggleGroup + AdwToggle (1.7)
Persistent bottom controls (player)AdwBottomSheet (1.6)
Wrapping content (tag chips)AdwWrapBox (1.7) — child-spacing/line-spacing, no spacing property
Inline view switching (cards, sidebars)AdwInlineViewSwitcher (1.7)
Full-width button in boxed listAdwButtonRow (1.6)
Sectioned sidebarAdwSidebar + AdwSidebarSection/AdwSidebarItem (1.9)
Sidebar that switches an AdwViewStackAdwViewSwitcherSidebar (1.9)
Keyboard shortcuts dialogAdwShortcutsDialog (1.8)
System monospace/document fontsAdwStyleManager get_monospace_font_name()/get_document_font_name() (1.7); CSS --monospace-font-family, --document-font-family
System accent colorAutomatic via portal; --accent-bg-color etc.
# AdwToggleGroup - view mode switching (note: Adw.Toggle objects, not buttons)
toggle_group = Adw.ToggleGroup()
toggle_group.add(Adw.Toggle(icon_name="view-grid-symbolic", name="grid"))
toggle_group.add(Adw.Toggle(icon_name="view-list-symbolic", name="list"))
toggle_group.connect("notify::active-name", lambda g, p: set_view(g.get_active_name()))
header.pack_start(toggle_group)

# AdwBottomSheet - music player controls
bottom_sheet = Adw.BottomSheet()
bottom_sheet.set_content(main_content)
bottom_sheet.set_sheet(player_controls)
bottom_sheet.set_open(True)
window.set_content(bottom_sheet)

# AdwWrapBox - tag display (child_spacing/line_spacing, NOT spacing)
wrap_box = Adw.WrapBox(child_spacing=6, line_spacing=6)
for tag in ["Python", "GTK", "GNOME"]:
    wrap_box.append(Gtk.Label(label=tag))

Verify, Then Claim

A widget or version claim is confirmed by the installed introspection data, not by memory: /usr/share/gir-1.0/Adw-1.gir and Gtk-4.0.gir carry version="1.x" (since) and deprecated-version="1.x" attributes on each class — parse them (attributes span multiple lines; plain grep on the class name misses them). A CSS class is confirmed by the shipped stylesheet: gresource extract /usr/lib/x86_64-linux-gnu/libadwaita-1.so.0 /org/gnome/Adwaita/styles/default-light-yaru-default.css (path varies by distro patching; gresource list shows what's there). Presence in the stylesheet proves a class exists; only the GIR/docs settle whether it is current or a deprecated alias (.dim-label still ships beside .dimmed). An icon name is confirmed by the installed theme:

find /usr/share/icons/Adwaita -name 'NAME-symbolic.svg' | head -1

Some icons ship inside GTK/libadwaita gresources, so an empty result is a strong signal rather than proof — gtk4-icon-browser is the exhaustive check.

Container Selection

ScenarioDefaultNotes
App windowAdwApplicationWindow + AdwHeaderBar in AdwToolbarViewRemember user size, start ~800x600
SettingsAdwPreferencesDialogPages, groups, search built in; present(parent)
List of settings/itemsAdwPreferencesGroup with rowsBoxed list style
Modal action / decisionAdwDialog / AdwAlertDialogAdaptive; bottom sheet on narrow screens
Primary actionSingle button, header bar endsuggested-action class; one per view
Destructive actiondestructive-action classPair with undo or confirmation

Navigation Selection

StructureDefault Pattern
Single viewNone needed
2-4 viewsAdwViewSwitcher in header bar + AdwViewSwitcherBar below breakpoint
Many/dynamic viewsAdwNavigationSplitView with AdwSidebar (1.9) or GtkListBox.navigation-sidebar
View switching via sidebarAdwViewSwitcherSidebar (1.9)
Hierarchical (drill-down)AdwNavigationView
Utility pane that overlays when narrowAdwOverlaySplitView

Adaptivity comes from AdwBreakpoint setters on the window (max-width: 600sp → set collapsed), never from swapping widget trees by hand.

Control Defaults

NeedDefaultInstead of
On/OffAdwSwitchRowCheckbox for settings
Choose one (few)AdwComboRowRadio buttons outside dialogs
Choose one (many)AdwComboRow + enable-searchLong unsearchable dropdowns
Text inputAdwEntryRowBare GtkEntry in lists
Multiline textGtkTextView in ScrolledWindow + card classBare unstyled text view
NumberAdwSpinRowText entry for numbers
One primary action with related variants (a + that can create several kinds of thing)AdwSplitButton — main action on the button, siblings in menu-modelA single button that silently picks one variant
Button in a boxed listAdwButtonRow (1.6)Hand-styled full-width GtkButton
Action in listAdwActionRow + one suffix buttonMultiple buttons per row
SearchGtkSearchBar + header toggle, set_key_capture_widget(window)Always-visible search box

List Widget Selection

ContentWidgetTie-breaker
Settings/preferencesAdwPreferencesGroupStatic rows, boxed style
Navigation/selection listGtkListBoxRow widgets, .navigation-sidebar class, fine under ~hundreds of rows
Large/dynamic dataGtkListViewRecycled widgets via factory — required for thousands of rows
Grid of itemsGtkGridViewSame factory model as ListView

Selection: Gtk.SingleSelection for navigation, Gtk.MultiSelection behind an explicit selection mode (header toggle + GtkActionBar for bulk actions). Factory/model code lives in developing-gtk-apps.

Iconography

Symbolic icons only (-symbolic, monochrome). Header bar buttons are icon-only with tooltips. Icons beyond the system theme (browse the GNOME Icon Library app) must be bundled as resources — a bare icon_name string only resolves from the installed theme.

ActionIcon (verified in Adwaita theme)
Add/Newlist-add-symbolic
Deleteuser-trash-symbolic
Settingsemblem-system-symbolic
Menuopen-menu-symbolic
Searchsystem-search-symbolic
Editdocument-edit-symbolic
Backgo-previous-symbolic
Drill-downgo-next-symbolic
Offlinenetwork-offline-symbolic
Warning / Errordialog-warning-symbolic / dialog-error-symbolic
Select modeselection-mode-symbolic
Check/Doneobject-select-symbolic
Closewindow-close-symbolic
Refresh/Syncview-refresh-symbolic
Open / Savedocument-open-symbolic / document-save-symbolic
Copyedit-copy-symbolic
Find in contentedit-find-symbolic
Linkinsert-link-symbolic
Attachmail-attachment-symbolic
Toggle sidebarsidebar-show-symbolic
New folderfolder-new-symbolic
Overflow/Moreview-more-symbolic
Sortview-sort-ascending-symbolic
Move up / downgo-up-symbolic / go-down-symbolic
Remove from listlist-remove-symbolic
Favoritestar-new-symbolic
Expand/Collapsepan-down-symbolic
Playmedia-playback-start-symbolic

Plausible-sounding names are routinely absent (chain-link-, attach-, dock-left-, view-sidebar-start-, emblem-ok-symbolic all fail on this system) — run any name not in this table through the find check in "Verify, Then Claim" before using it.

Designing Against Platform Limits

Some controls cannot work on GNOME Wayland without a companion shell extension: positioning a window, keeping it above others, hiding it from the dock, grabbing a global shortcut. The design question is what the UI does when the capability is absent — and the answer is never "look like it worked".

StateDoNot
Capability unavailableShow the control insensitive, with a tooltip naming what is missingLeave it interactive; a toggle that latches while nothing happens reads as a bug in your app
Capability unavailableKeep the control presentHide it — a control that appears and disappears between sessions is harder to learn than one that greys out
Degraded, not brokenSay what still works ("content and size still persist")Imply total failure
pin_button.set_sensitive(available)
pin_button.set_tooltip_text(
    "Keep on Top" if available else
    "Keep on Top needs the … extension — Wayland does not let apps raise "
    "their own windows")

Architecture for this lives in developing-gtk-apps (gnome-shell-companion-reference.md).

Feedback Selection

ScenarioDefaultDetails
Action doneAdwToastShort message, optional button
Destructive actionAdwToast + Undo buttonPrefer over confirmation dialog
Error (recoverable)AdwToastBrief, auto-retry silently
Error (blocking) / needs decisionAdwAlertDialogCancel first, specific verb last, DESTRUCTIVE appearance
Persistent state (offline, auth)AdwBannerTop of content, optional button
Data not being savedAdwBanner, and keep it upOngoing condition, not an event. A toast is missed while typing, and the cost of missing it is lost work. Log once, show until fixed
Capability missing (needs a shell extension)Insensitive control + tooltipNever a dialog on startup; it is a limit, not an error
Short wait (<5s)AdwSpinnerNo progress bar
Long operationGtkProgressBar + text"13 of 42 processed"
Empty listAdwStatusPageIcon + title + pill+suggested-action button
Event while backgroundedGNotificationNot toasts — those need the window visible

Escalation: Toast (transient) → Banner (persists) → Dialog (requires action).

Typography & Color

Style classes, not custom CSS: title-1…title-4, heading, body, caption, caption-heading, monospace, numeric, dimmed — and card, pill, flat, boxed-list, navigation-sidebar, toolbar, osd, error/warning/success (all present in the 1.9 stylesheet). Colors via var(--accent-color)-style variables only — full table in gnome-hig-reference.md.

Writing: header capitalization for buttons/menus/titles, sentence capitalization for descriptions/switch labels, no trailing periods, verbs not "OK". Details in gnome-hig-reference.md.

Definition of Done

The design is implemented when the assembled window has been rendered and looked at, and every line checks out against the code.

Render first. Launch the app (or a screenshot harness — developing-gtk-apps has the run/render plumbing) and inspect the actual window before calling anything done; compiling and passing tests draw zero frames. Check in the render:

  • Close/minimise/maximise are visible in every pane state — libadwaita puts window controls on the outermost header bar, so show-end-title-buttons(false) on the wrong pane's header removes them entirely.
  • The shortcuts dialog shows its accelerators — accelerator strings in code are plain <Control>n; XML-escaped entities (&lt;Control&gt;n) belong only inside .ui files.
  • Sidebars/panes start in their intended state — set the split view's show-sidebar explicitly and bind the toggle from it; a sync_create bind from a default-inactive toggle hides the sidebar at launch.
  • Content fills the window — a custom widget sets vexpand/hexpand on itself; a scroller expanding inside a 30px-tall parent means the parent lacks the flag.

Then line checks:

  • Every Adw/Gtk class used appears non-deprecated in the installed GIR (the "What's Current" table has the swaps; anything unfamiliar goes through "Verify, Then Claim").
  • Dialogs are AdwDialog subclasses presented with present(parent).
  • Windows that can go narrow have AdwBreakpoints driving collapsed/switcher-bar changes.
  • Colors and fonts come from var(--…) variables or style classes — zero hardcoded hex values.
  • Text uses .dimmed, never .dim-label.
  • Every icon-only button has tooltip_text; every icon name either exists in the Adwaita theme or is bundled.
  • Each user action has exactly one affordance in the visible view — count across header bar, sidebar, and content together (a header +, a sidebar pill, and a content pill for the same "New" is two too many), and at most one empty state is on screen at a time.
  • At most one suggested-action per view and destructive actions carry undo or an AdwAlertDialog confirmation.
  • Controls for capabilities the platform may not provide are insensitive with an explanatory tooltip, never silently inert.
  • Failures that lose user data raise a persistent banner, not a toast.
  • Labels follow the capitalization table (header caps for buttons/menus, sentence caps for descriptions).

Non-GTK Apps (Qt/PySide6)

No maintained Adwaita Qt theme exists — style via QSS using the color variables above, map header bar → fixed toolbar, and reuse this skill's pattern/spacing/typography decisions. Test beside a native GNOME app.

Reference Files

The question in front of youRead
"How is this pattern wired?" — the AdwAlertDialog response contract (who closes the dialog, the Enter path), AdwSidebar sections/selection/context menus, which containers already scroll, theming GtkTextTag colors for dark mode, search, file dialogs, breakpoints, menus, writing style, the color-variable tablegnome-hig-reference.md
"How do I build drag & drop / tabs (AdwTabView) / system notifications / zoom gestures / paned views / an onboarding carousel / widget-scoped shortcuts?"gnome-advanced-patterns.md

FAQ

What does the designing-gnome-ui skill do?

Use for every user-visible change in a GNOME app, new or existing, whether or not the request uses design vocabulary. Trigger on the repo rather than the wording — if it depends on gtk4/libadwaita (or is a GNOME-targeted Qt/PySide6 app), anything a user can see or interact with goes through this skill, including requests phrased purely as symptoms ("can I right-click to delete", "the window opens too small", "reordering doesn't work"). Covers choosing widgets, icons, dialogs, menus, sidebars, navigation, and empty states; interaction bugs in context menus, drag-and-drop reordering, window sizing, layout, duplicate affordances, and controls missing or inert at launch; and HIG review. Complements developing-gtk-apps, which owns architecture, threading, language syntax, and build/test plumbing.

How do I install designing-gnome-ui?

Run npx skills add https://github.com/mhagrelius/dotfiles --skill designing-gnome-ui in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/designing-gnome-ui/ (personal) or .claude/skills/designing-gnome-ui/ (project).

Which AI agents can use designing-gnome-ui?

Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.

Is designing-gnome-ui safe to install?

No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.

Who maintains designing-gnome-ui?

It is published by mhagrelius in mhagrelius/dotfiles. It has 100 recorded installs.

More from mhagrelius/dotfiles

View all →

dotnet-10-csharp-14

mhagrelius/dotfiles

Use when building .NET 10 or C 14 applications; when using minimal APIs, modular monolith patterns, or feature folders; when implementing HTTP resilience, Options pattern, Channels, or validation; when seeing outdated patterns like old extension method syntax

Backend & APIs1.9K installs

developing-gtk-apps

mhagrelius/dotfiles

Use for any change to a GTK 4/libadwaita app, new or existing, whether or not the request mentions GTK. Trigger on the repo rather than the wording — if Cargo.toml depends on gtk4/libadwaita, or sources import gi/Gtk (Python) or use Gtk (Vala), this applies to every change to that app, including requests phrased purely as symptoms ("reordering doesn't work", "pressing enter should continue the list", "the window opens too small"). Covers app boilerplate and new features; behaviour bugs in drag-and-drop, context menus, keyboard and text editing, focus, selection, and window sizing; threading, signals, and lifecycle; gtk-rs calls that fail to compile; GSettings, resources, packaging, and tests. Delegates widget choice, layout, and HIG to designing-gnome-ui.

Frontend & Design120 installs

building-tui-apps

mhagrelius/dotfiles

Use when building interactive terminal dashboards or full-screen terminal applications; when implementing keyboard navigation, live data updates, or multi-panel layouts; when TUI is flickering, slow, or unresponsive; when handling terminal resize events

100 installs

using-typescript-lsp

mhagrelius/dotfiles

Use when working with TypeScript or JavaScript code and typescript-lsp plugin is enabled - for finding references, checking types, navigating definitions, or verifying type correctness

Use when building AI agents with Microsoft Agent Framework (Semantic Kernel + AutoGen unified); when implementing memory or context providers; when threads won't deserialize; when workflow checkpointing fails; when migrating from Semantic Kernel or AutoGen; when seeing ChatAgent or AgentThread errors

AI & Agents42 installs

working-with-aspire

mhagrelius/dotfiles

Use when building distributed apps with Aspire; orchestrating .NET, JavaScript, Python, or polyglot services; when environment variables or service discovery aren't working; when migrating from .NET Aspire 9 to 13+ or Community Toolkit; when seeing AddNpmApp deprecated errors; when OTEL not appearing in dashboard; when ports change on restart breaking OAuth; when configuring MCP server for AI assistants; when debugging Aspire apps and need to check resource status or logs

Backend & APIs42 installs

Popular frontend & design skills

View category →

setup-matt-pocock-skills

mattpocock/skills

Configure this repo for the engineering skills: set up its issue tracker, triage label vocabulary, and domain doc layout. Run once before first use of the other engineering skills.

Frontend & Design1.1M installs

frontend-design

anthropics/skills

Guidance for distinctive, intentional visual design when building new UI or reshaping an existing one. Helps with aesthetic direction, typography, and making choices that don't read as templated defaults.

OfficialFrontend & Design1M installs

hyperframes-animation

heygen-com/hyperframes

All animation knowledge for HyperFrames — atomic motion rules, multi-phase scene blueprints, scene transitions, broader motion-design techniques, AND the seven runtime adapters (GSAP default, plus Lottie, Three.js, Anime.js, CSS keyframes, Web Animations API, TypeGPU). Use for any motion or animation task: pick 2-4 rules and compose, or load a blueprint, or look up runtime-specific API (e.g. GSAP eases / Lottie player / Three.js mixer). Also covers auditing an existing composition's choreography (animation map) and 24 named text-animation effects. HyperFrames-native: single paused timeline, seek-safe, deterministic.

prototype

mattpocock/skills

Build a throwaway prototype to answer a design question. Use when the user wants to sanity-check whether a state model or logic feels right, or explore what a UI should look like.

Frontend & Design999.2K installs

hyperframes-core

heygen-com/hyperframes

The HyperFrames composition contract — build one renderable project. Use for composition structure, the data- timing attributes, class="clip", tracks, sub-compositions, variables, framework-owned media playback, deterministic-render rules, and validation. Read before writing composition HTML.

Frontend & Design930.5K installs

vercel-react-best-practices

vercel-labs/agent-skills

React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.

OfficialFrontend & Design843.1K installs