Repository navigation
Description
Summary
On macOS, setPadding (and the deprecated widgetSetEdgeInsets it aliases) is implemented for only four AppKit class families. It silently no-ops on every other widget, including Button and text labels, which the design system needs to pad. A caller has no way to tell that the call did nothing.
Environment
- Perry 0.5.1531 (local build)
- macOS, Darwin 25.6.0, arm64
- Native macOS target (
perry-ui-macos)
Cause (confirmed in source)
setPadding and widgetSetEdgeInsets compile to the same FFI, perry_ui_widget_set_edge_insets (crates/perry-codegen/src/lower_call/ui_styling.rs), which calls set_edge_insets in crates/perry-ui-macos/src/widgets/padding.rs. That function branches on four classes only — NSStackView, NSTextField (and only when the widget installed the Perry inset cell), NSTextView, NSScrollView — and then ends. There is no catch-all, so any other widget class falls through and the call is a no-op. Labels install no inset cell (only textfield.rs and securefield.rs do), so an NSTextField label also no-ops.
What works vs what no-ops
Padding works:
| Handled class | Widgets |
|---|---|
NSStackView |
hstack, vstack, zstack, navstack, bottom_nav, toggle |
NSTextField + inset cell |
textfield, securefield |
NSTextView |
textarea, rich_text |
NSScrollView |
scrollview, image_gallery |
Padding no-ops:
| Unhandled class | Widgets |
|---|---|
NSButton |
button |
NSTextField label (no inset cell) |
text, toast, attributed_text, text_registry |
NSImageView |
image, qrcode |
NSDatePicker |
date_picker, calendar |
NSComboBox |
combobox |
NSPopUpButton |
picker |
NSSlider |
slider |
NSProgressIndicator |
progressview |
NSBox |
divider, form |
NSTableView |
table, lazyvstack, command_palette |
NSOutlineView |
tree_view |
plain NSView |
adbanner, spacer |
NSWindow |
sheet |
Impact
Button and text labels are the clear cases: the design system sizes a medium button by its horizontal padding (0 var(--space-5)), and pads label chips. With the no-op, a button cannot be padded, so its width has to be hard-coded. Other controls (slider, progress, spacer) may not need padding, but the silent no-op gives a caller no signal either way.
For comparison, iOS applies button padding — UIButton via configuration.setContentInsets (fallback setContentEdgeInsets) in perry-ui-ios/src/widgets/padding.rs — so this is a macOS-specific gap, not a cross-platform limitation.
Suggested fix
Give the common leaf widgets a real padding path on macOS, starting with the two the design system needs: NSButton (content insets via NSButton.Configuration.contentInsets, or a content wrapper) and NSTextField labels. Where a widget genuinely cannot be padded, consider a debug-time warning rather than a silent no-op so a caller learns the call had no effect.
Related
- fix(perry/ui): padding dropped on non-stack widgets on Apple backends (macOS/iOS/tvOS/visionOS) #9954 — "padding dropped on non-stack widgets on Apple backends" (closed). That fix added padding for
TextField,TextArea, andSecureField. This issue is the unfinished tail of the same problem:Button, text labels, and the other leaf widgets listed above still no-op.
Scope
macOS target. Every widget whose backing class is not one of the four handled families.
Activity
proggeramlug commentedon Sep 14, 2026
Fixed by merge train 186r (#10247) at eb13fa1.