Buttons are where most apps first meet Liquid Glass. SwiftUI gives you two built-in glass button styles, .glass and .glassProminent, plus the lower-level glassEffect modifier for anything custom. This guide covers when to use each, with copy-paste code and a fallback for apps that still support iOS 18.

For the broader Liquid Glass API – cards, sheets, toolbars, morphing – see our complete Liquid Glass SwiftUI guide.

The Two Built-In Glass Button Styles

HStack {
    Button("Cancel") { dismiss() }
        .buttonStyle(.glass)

    Button("Post") { publish() }
        .buttonStyle(.glassProminent)
}
StyleLooks likeUse forPre-iOS 26 equivalent
.glassClear, translucent glassSecondary actions.bordered
.glassProminentOpaque glass filled with the tint colorThe primary action on screen.borderedProminent

Rule of thumb: one .glassProminent button per screen or group, like a default button. If everything is prominent, nothing is.

Tinting Glass Buttons

Both styles respect .tint(). On .glassProminent the tint fills the button. On .glass it colors the label and subtly tints the glass.

Button("Follow") { follow() }
    .buttonStyle(.glassProminent)
    .tint(.blue)

Button("Unfollow", role: .destructive) { unfollow() }
    .buttonStyle(.glass)
    .tint(.red)

Use your app's accent color for the prominent button rather than tinting every control. Liquid Glass is designed to let content show through, and heavy tints work against that.

Sizes and Shapes

Glass buttons work with the standard sizing and shape modifiers:

Button("Large") { }
    .buttonStyle(.glass)
    .controlSize(.large)

Button("Capsule") { }
    .buttonStyle(.glass)
    .buttonBorderShape(.capsule)

Circular icon buttons

The most common glass button in iOS 26 apps is a round icon button, for things like a floating compose button over a timeline:

Button {
    showComposer = true
} label: {
    Image(systemName: "square.and.pencil")
        .font(.title2)
        .frame(width: 44, height: 44)
}
.buttonStyle(.glassProminent)
.buttonBorderShape(.circle)
.accessibilityLabel("New post")

Always add an accessibilityLabel to icon-only buttons. VoiceOver will otherwise read the SF Symbol name.

Custom Glass Buttons With glassEffect

When you need control the button styles don't give you, apply glassEffect directly. The key detail is .interactive(): it gives the glass the press response (the subtle scale and shimmer) that the built-in styles get automatically.

Button { toggleLike() } label: {
    Image(systemName: isLiked ? "heart.fill" : "heart")
        .font(.title3)
        .foregroundStyle(isLiked ? .pink : .primary)
        .frame(width: 48, height: 48)
}
.buttonStyle(.plain)
.glassEffect(.regular.tint(isLiked ? .pink.opacity(0.3) : nil).interactive(), in: .circle)

Breaking down the Glass value:

  • .regular – the standard material. Start here.
  • .clear – more transparent, for controls over photos or video where you want media to show through. It needs a dimming layer behind it for legibility.
  • .tint(_:) – adds color to the glass itself.
  • .interactive() – makes the glass react to touch. Use it on anything tappable.

Use .buttonStyle(.plain) underneath so the default button style doesn't draw its own background beneath the glass.

Grouping Buttons in a GlassEffectContainer

Glass can't sample other glass, so several glass buttons placed near each other can look muddy. Wrap them in a GlassEffectContainer so they render together and blend when they're close:

GlassEffectContainer(spacing: 12) {
    HStack(spacing: 12) {
        ForEach(actions) { action in
            Button { action.run() } label: {
                Image(systemName: action.symbol)
                    .frame(width: 44, height: 44)
            }
            .buttonStyle(.plain)
            .glassEffect(.regular.interactive(), in: .circle)
            .accessibilityLabel(action.title)
        }
    }
}

The container's spacing controls how close elements must be before their glass starts to merge. To make several buttons read as one capsule, give them the same glassEffectUnion(id:namespace:):

@Namespace private var glass

GlassEffectContainer {
    HStack(spacing: 0) {
        Button("Day") { }
            .padding()
            .glassEffect(.regular.interactive())
            .glassEffectUnion(id: "range", namespace: glass)
        Button("Week") { }
            .padding()
            .glassEffect(.regular.interactive())
            .glassEffectUnion(id: "range", namespace: glass)
    }
}

Backward Compatibility: iOS 18 Fallback

If your app still supports iOS 18 or earlier, wrap the styles in a small helper so call sites stay clean:

extension View {
    @ViewBuilder
    func adaptiveGlassButton(prominent: Bool = false) -> some View {
        if #available(iOS 26.0, *) {
            if prominent {
                self.buttonStyle(.glassProminent)
            } else {
                self.buttonStyle(.glass)
            }
        } else {
            if prominent {
                self.buttonStyle(.borderedProminent)
            } else {
                self.buttonStyle(.bordered)
            }
        }
    }
}

// Usage
Button("Post") { publish() }
    .adaptiveGlassButton(prominent: true)

The bordered styles are the closest visual match from earlier iOS versions, so layouts behave the same on both.

Common Mistakes

  • Glass on the content layer. Apple's guidance is that Liquid Glass belongs on controls and navigation that float above content. A list where every row is glass is the most common misuse. See Apple's HIG for social apps.
  • Glass on glass. A glass button inside a glass card doesn't render well. Use a plain or tinted button inside glass containers.
  • Forgetting .interactive() on custom glass buttons, so they feel dead to the touch.
  • Custom glass in toolbars. Toolbar items get glass automatically in iOS 26. Adding glassEffect yourself doubles it up.
  • Ignoring accessibility settings. The system adapts glass automatically for Reduce Transparency and Increase Contrast, but only if you use the system materials rather than faking glass with blur and opacity.

Frequently Asked Questions

What's the difference between .glass and .glassProminent in SwiftUI?

.glass is a translucent glass button for secondary actions. .glassProminent fills the glass with the tint color for the primary action. They correspond to .bordered and .borderedProminent on earlier iOS versions.

How do I make a circular Liquid Glass button in SwiftUI?

Apply .buttonStyle(.glass) or .glassProminent and add .buttonBorderShape(.circle), giving the label a fixed square frame. For custom buttons, use .glassEffect(.regular.interactive(), in: .circle).

Why doesn't my custom glass button respond when tapped?

Add .interactive() to the Glass value, as in .glassEffect(.regular.interactive()). Without it the glass doesn't react to touches.

Can I use glass button styles on iOS 18?

No. They require iOS 26 or later. Use an #available check and fall back to .bordered and .borderedProminent.

See Liquid Glass in a Real App

Skyscraper is built in SwiftUI with Liquid Glass throughout. If you're building for Bluesky or the AT Protocol, it's a good reference for how the design language works in a busy social timeline.

Download Skyscraper for iOS →

Related Reading