Be Careful Using SwiftUI's buttonStyle Modifier With List swipeActions
SwiftUI has a really useful swipeActions
modifier on List rows - see the SwiftUI docs here. It lets you add a swipe gesture to show action buttons on that row. For example, a delete button. (You've seen this in apps like Mail, where you swipe to get actions like Move or Archive/Delete.)
When I was adding it to an app recently, I found a bit of a strange bug. I just couldn't get the swipeActions
to work; the gesture did nothing.
I discovered this article about swipeActions on samwize.com and it identified my bug:
If you were to apply any button style (eg. system
borderless
or custom styles), then the button will NOT show up at all.
The problem is, if you set a button style on a parent view, then it'll apply to all of the buttons within that view. That's usually a great thing about SwiftUI: you can apply a style to all subviews of a view by setting the modifier at a top level view. But for swipeActions
to work, you'll have to explicitly use the modifier .buttonStyle(.automatic)
on your buttons in swipeActions
to set buttonStyle
back to the default:
.swipeActions {
Button {
// some action
} label: {
Label("Some Action", systemImage: "some.action.image")
}
.buttonStyle(.automatic)
}
I think I understand the source of the problem - the buttonStyle
has to be .automatic
for the buttons to be rendered properly in swipeActions
, and if you have some custom style then it could be really awkward to render.
But I strongly disagree with the solution the SwiftUI team have gone with, where the swipeActions
modifier has no effect with a custom buttonStyle
. Better to make the core action work, and break the styling, than to honour the styling and make the action silently fail.
If you liked this article, please consider buying me a coffee to support my writing.
Published on 10 February 2025