Icons
Button.iconName and MenuItem.iconName (see the Widget Reference)
both take a freedesktop icon name, the same vocabulary GTK/GNOME apps use, as the canonical
cross-platform identifier. The mapping below is shared by both widgets; see
Menu Bar for why MenuItem.iconName renders on macOS but is
intentionally invisible on GNOME.
Linux: native, direct
Section titled “Linux: native, direct”On GTK, a freedesktop name resolves directly through the system icon theme: gtk.Button.setIconName
for icon-only buttons, or an adw.ButtonContent that pairs an icon with a label. There is no
translation step.
macOS: mapped to SF Symbols, with pass-through
Section titled “macOS: mapped to SF Symbols, with pass-through”swift/Sources/NDShell/Icons.swift maps a known subset of freedesktop names to their closest SF
Symbol equivalent:
| freedesktop name | SF Symbol |
|---|---|
list-add |
plus |
document-new |
square.and.pencil |
edit-delete / user-trash |
trash |
edit-find / system-search |
magnifyingglass |
view-list |
list.bullet |
checklist |
checklist |
mail-send |
paperplane |
document-open |
folder |
emblem-shared |
person.crop.circle |
go-previous |
chevron.backward |
go-next |
chevron.forward |
window-close |
xmark |
document-save |
square.and.arrow.down |
view-refresh |
arrow.clockwise |
open-menu |
ellipsis.circle |
view-pin / pin |
pin |
starred |
star.fill |
non-starred |
star |
edit-copy |
doc.on.doc |
edit-cut |
scissors |
edit-paste |
doc.on.clipboard |
edit-undo / edit-redo |
arrow.uturn.backward / arrow.uturn.forward |
go-up / go-down / go-home |
chevron.up / chevron.down / house |
pan-up / pan-down / pan-start / pan-end |
matching chevron.* |
network-offline |
wifi.slash |
process-stop |
xmark.octagon |
zoom-in / zoom-out / zoom-original |
plus.magnifyingglass / minus.magnifyingglass / 1.magnifyingglass |
media-playback-start / -pause / -stop |
play.fill / pause.fill / stop.circle |
preferences-system / emblem-system |
gearshape |
dialog-information / -warning / -error / -question |
info.circle / exclamationmark.triangle / exclamationmark.triangle / questionmark.circle |
folder-new / user-home / bookmark-new |
folder.badge.plus / house / bookmark |
document-edit / document-print |
pencil / printer |
changes-prevent / changes-allow |
lock / lock.open |
The full table lives in swift/Sources/NDShell/Icons.swift (roughly 90 names); it grows as new
names are needed.
If iconName isn’t in the table, it passes through verbatim as an SF Symbol name, so a direct
SF Symbol name (e.g. "gearshape") works on macOS without an entry here. If neither the
mapping nor the direct name resolves to a real symbol, the macOS backend falls back to title-only
and prints an ND_WARN unknown iconName diagnostic instead of failing silently.
Symbol configuration
Section titled “Symbol configuration”Resolved SF Symbols ship configured, not bare: a <button iconName> derives its symbol’s point
size from the button font, uses the .large scale when icon-only and .medium next to a label,
and prefers hierarchical rendering (the HIG guidance for control glyphs). <image> exposes the
same axes as create-only props: symbolScale (small/medium/large), symbolWeight
(regular/medium/semibold/bold), and symbolRenderingMode
(monochrome/hierarchical/multicolor). On GTK, symbolScale maps to the icon pixel size;
weight and rendering mode have no GTK peer (symbolic icons carry one stroke weight and recolor via
CSS) and are deliberately inert there.
macOS 27 hides menu-item symbol images by default
Section titled “macOS 27 hides menu-item symbol images by default”Starting with macOS 27, NSMenu hides menu-item symbol images unless the item opts in — the
revised HIG wants menu icons used sparingly. MenuItem.iconName is therefore advisory on macOS 27:
the system may not show it. An item that must keep its image sets iconVisible alongside
iconName, which maps to NSMenuItem.preferredImageVisibility = .visible on macOS 27 and is a
no-op on earlier releases (images still render by default there).