BS
BleepingSwift
Published on

> Building Interactive Glass Controls in SwiftUI

Authors
  • avatar
    Name
    Mick MacCallum
    Twitter
    @0x7fs

Static glass surfaces look great, but interactive glass feels native to iOS 26. When you add the .interactive() modifier to a glass effect, touches trigger subtle scaling, a shimmer across the surface, and illumination at the touch point. These micro-interactions make buttons feel responsive and polished.

Adding Interactivity

Chain .interactive() onto your glass effect to enable touch feedback:

import SwiftUI

struct InteractiveGlassButton: View {
    var body: some View {
        Button("Get Started") {
            // action
        }
        .padding(.horizontal, 24)
        .padding(.vertical, 14)
        .foregroundStyle(.white)
        .glassEffect(.regular.interactive())
    }
}

Now when you tap the button, the glass surface responds with a subtle press animation, a shimmer that ripples across the surface, and a glow that emanates from your touch point. These effects are built into the system, so they automatically feel consistent with the rest of iOS 26.

Combining with Tinting

Interactive glass works great with tinted surfaces:

// Primary action with blue tint
Button("Continue") { }
    .padding()
    .foregroundStyle(.white)
    .glassEffect(.regular.tint(.blue).interactive())

// Destructive action with red tint
Button("Delete") { }
    .padding()
    .foregroundStyle(.white)
    .glassEffect(.regular.tint(.red.opacity(0.8)).interactive())

// Subtle secondary action
Button("Maybe Later") { }
    .padding()
    .foregroundStyle(.white)
    .glassEffect(.regular.tint(.gray.opacity(0.5)).interactive())

The order of modifiers matters. You can write .regular.tint(.blue).interactive() or .regular.interactive().tint(.blue) and get the same result, but keeping a consistent ordering makes your code easier to read.

Using Glass Button Styles

SwiftUI also provides dedicated button styles for common glass patterns:

// Standard glass button
Button("Secondary Action") { }
    .buttonStyle(.glass)

// Prominent glass button with more visual weight
Button("Primary Action") { }
    .buttonStyle(.glassProminent)

The .glass style creates a translucent secondary button, while .glassProminent produces a more opaque primary button. Both include built-in interactivity.

These styles are more limited than the .glassEffect() modifier since you can't customize the shape or add tinting, but they're perfect when you just need standard buttons that match system UI.

Building a Custom Control

Here's a segmented control built entirely with interactive glass:

import SwiftUI

struct GlassSegmentedControl: View {
    @Binding var selection: Int
    let options: [String]

    var body: some View {
        GlassEffectContainer(spacing: 8) {
            HStack(spacing: 4) {
                ForEach(options.indices, id: \.self) { index in
                    Button {
                        withAnimation(.snappy) {
                            selection = index
                        }
                    } label: {
                        Text(options[index])
                            .foregroundStyle(selection == index ? .white : .white.opacity(0.7))
                            .padding(.horizontal, 16)
                            .padding(.vertical, 10)
                    }
                    .glassEffect(
                        selection == index
                            ? .regular.tint(.blue).interactive()
                            : .regular.interactive()
                    )
                }
            }
            .padding(4)
            .glassEffect(.regular, in: .capsule)
        }
    }
}

// Usage
struct ContentView: View {
    @State private var tab = 0

    var body: some View {
        VStack {
            GlassSegmentedControl(
                selection: $tab,
                options: ["Day", "Week", "Month"]
            )
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.indigo.gradient)
    }
}

Each segment is an interactive glass button, with the selected one showing a blue tint. The whole control sits inside an outer glass capsule, creating a layered appearance.

Icon Buttons with Touch Feedback

For icon-only buttons, interactive glass makes the tap target clear:

import SwiftUI

struct GlassIconBar: View {
    var body: some View {
        GlassEffectContainer(spacing: 16) {
            HStack(spacing: 12) {
                iconButton(systemName: "house.fill")
                iconButton(systemName: "magnifyingglass")
                iconButton(systemName: "heart.fill")
                iconButton(systemName: "person.fill")
            }
            .padding(.horizontal, 8)
            .padding(.vertical, 8)
            .glassEffect(.regular, in: .capsule)
        }
    }

    func iconButton(systemName: String) -> some View {
        Button {
            // action
        } label: {
            Image(systemName: systemName)
                .font(.title3)
                .foregroundStyle(.white)
                .frame(width: 44, height: 44)
        }
        .glassEffect(.regular.interactive(), in: .circle)
    }
}

The circular glass buttons provide clear affordance for tapping, and the interactive effect confirms each touch.

Floating Action Button

Here's a polished floating action button with proper interactive feedback:

import SwiftUI

struct FloatingActionButton: View {
    let icon: String
    let color: Color
    let action: () -> Void

    var body: some View {
        Button(action: action) {
            Image(systemName: icon)
                .font(.title2)
                .fontWeight(.semibold)
                .foregroundStyle(.white)
                .frame(width: 56, height: 56)
        }
        .glassEffect(.regular.tint(color).interactive(), in: .circle)
        .shadow(color: color.opacity(0.3), radius: 8, y: 4)
    }
}

// Usage
struct ContentView: View {
    var body: some View {
        ZStack(alignment: .bottomTrailing) {
            ScrollView {
                // content
            }

            FloatingActionButton(
                icon: "plus",
                color: .blue
            ) {
                // create something
            }
            .padding()
        }
    }
}

The combination of tinted interactive glass and a subtle shadow creates a button that feels tactile and inviting.

Media Controls

Interactive glass is perfect for media playback controls:

import SwiftUI

struct GlassMediaControls: View {
    @State private var isPlaying = false

    var body: some View {
        GlassEffectContainer(spacing: 24) {
            HStack(spacing: 20) {
                controlButton(icon: "backward.fill") { }

                Button {
                    isPlaying.toggle()
                } label: {
                    Image(systemName: isPlaying ? "pause.fill" : "play.fill")
                        .font(.title)
                        .foregroundStyle(.white)
                        .frame(width: 64, height: 64)
                        .contentTransition(.symbolEffect(.replace))
                }
                .glassEffect(.regular.tint(.white.opacity(0.2)).interactive(), in: .circle)

                controlButton(icon: "forward.fill") { }
            }
        }
    }

    func controlButton(icon: String, action: @escaping () -> Void) -> some View {
        Button(action: action) {
            Image(systemName: icon)
                .font(.title2)
                .foregroundStyle(.white)
                .frame(width: 48, height: 48)
        }
        .glassEffect(.regular.interactive(), in: .circle)
    }
}

The play/pause button is slightly larger and has a subtle tint to draw attention as the primary control, while the skip buttons use plain interactive glass.

Performance Notes

Interactive glass effects are GPU-accelerated and optimized for 60fps animations. You can have multiple interactive glass elements on screen without performance concerns. The system automatically handles the touch tracking and animation timing.

That said, don't put dozens of interactive glass elements in a scrolling list. For large collections, consider using glass styling only for selected or highlighted items, or use standard button styles and reserve glass for floating controls outside the scroll area.

Accessibility

When users enable Reduce Motion in accessibility settings, the shimmer and touch-point illumination effects are automatically toned down. The button still provides feedback, but through more subtle means. You don't need to write any code to support this; the system handles it automatically.

For users with Increase Contrast enabled, interactive glass elements show clearer borders and more distinct pressed states, making it easier to see which element is being touched.

subscribe.sh

// Stay Updated

Get notified when I publish new tutorials on Swift, SwiftUI, and iOS development. No spam, unsubscribe anytime.

>

By subscribing, you agree to our Privacy Policy.