You can use a FocusState
to track which button is currently selected by keyboard navigation. Using this, you can write a custom ButtonStyle
that creates your custom focus effect when the button is focused. You can turn off the default focus effect (the blue outline) by using .focusEffectDisabled()
.
To pass the focus state to the ButtonStyle
is a bit difficult. The isFocused
environment value somehow doesn't work here. You can modify each button individually with a .buttonStyle
modifier with different parameters like in Benzy Neez's answer, but I would prefer to use a custom environment value.
For example, here is a button style that enlarges the button when it is focused.
struct MyButtonStyle: ButtonStyle {
@Environment(\.customFocus) var focus
func makeBody(configuration: Configuration) -> some View {
configuration.label
.scaleEffect(focus ? 1.5 : 1)
}
}
struct CustomFocusKey: EnvironmentKey {
static let defaultValue = false
}
extension EnvironmentValues {
var customFocus: Bool {
get { self[CustomFocusKey.self] }
set { self[CustomFocusKey.self] = newValue }
}
}
You can use a ViewModifier
to pass the focus state:
struct CustomFocusModifier: ViewModifier {
@FocusState var focus: Bool
func body(content: Content) -> some View {
content
.focused($focus)
.environment(\.customFocus, focus)
}
}
extension View {
func customFocus() -> some View {
modifier(CustomFocusModifier())
}
}
Example usage:
HStack {
Button("Foo") { ... }
.customFocus()
Button("Bar") { ... }
.customFocus()
}
.buttonStyle(MyButtonStyle())
.focusEffectDisabled()