Skip to content

Bring SwiftUI’s iOS 26 glass APIs to earlier deployments with lightweight shims—keep your UI consistent on iOS 18+, and automatically defer to the real implementations wherever they exist.

Notifications You must be signed in to change notification settings

Aeastr/UniversalGlass

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

91 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

UniversalGlass Icon

UniversalGlass

Bring SwiftUI's iOS 26 glass APIs to earlier deployments with lightweight shims—keep your UI consistent on iOS 17+, yet automatically defer to the real implementations wherever they exist.

Swift 6.0+ iOS 17+ macOS 13+ tvOS 17+ watchOS 10+ visionOS 1+

Preview

Overview

OS 26 introduces new SwiftUI glass APIs, but these only ship on the latest platforms. UniversalGlass offers compatibility layers so your code stays unified on older systems, then quietly defers to Apple's implementation where available.

  • Glass for every surface – Apply universalGlassEffect to any view with tinting and interactivity
  • Native-feeling buttons.universalGlass() and .universalGlassProminent() button styles
  • Containers & morphingUniversalGlassEffectContainer with union/ID helpers for glass grouping
  • Backports – Optional UniversalGlassBackports target for .glass and .glassEffect syntax

Installation

dependencies: [
    .package(url: "https://github.com/Aeastr/UniversalGlass.git", branch: "main")
]
import UniversalGlass
Target Description
UniversalGlass Main module with glass effects, button styles, and containers
UniversalGlassBackports Optional shorthand APIs (.glass, .glassEffect, etc.)

Usage

Glass Effects

Text("Hello")
    .universalGlassEffect(.regular.tint(.purple))

With a custom shape:

Circle()
    .frame(width: 120, height: 120)
    .universalGlassEffect(in: Circle())

See Effects for configurations, fallback customization, and transitions.

Button Styles

Button("Join Beta") { }
    .buttonStyle(.universalGlassProminent())
    .tint(.pink)

See Button Styles for routing behaviour and material fallback details.

Effect Containers

@Namespace private var ns

UniversalGlassEffectContainer {
    HStack {
        AvatarView()
            .universalGlassEffect()
            .universalGlassEffectUnion(id: "profile", namespace: ns)

        DetailsView()
            .universalGlassEffect()
            .universalGlassEffectUnion(id: "profile", namespace: ns)
    }
}

See Containers for grouping behaviour and Container Internals for the fallback pipeline.

Backports

import UniversalGlassBackports

Button("RSVP") {}
    .buttonStyle(.glassProminent)

See Backports for the full API surface.

Customization

Tinting and Interactivity

.universalGlassEffect(.regular.tint(.cyan))
.universalGlassEffect(.regular.interactive())

Fallback Materials

Override what renders on older OS versions:

.universalGlassEffect(.regular.fallback(material: .thin))
.universalGlassEffect(.thick.fallback(material: .regular, tint: .blue.opacity(0.2)))

Shadows

.universalGlassEffect(.regular.shadow(UniversalGlassShadow(color: .red, radius: 12)))
.universalGlassEffect(.regular.shadow(.none))

Global Rendering Mode

Force all effects in a hierarchy to use a specific renderer:

MyApp()
    .universalGlassRenderingMode(.material)  // Force fallback

Chaining

All modifiers chain:

.universalGlassEffect(
    .ultraThick
        .fallback(material: .thin, tint: .cyan.opacity(0.3))
        .shadow(UniversalGlassShadow(color: .blue, radius: 16))
        .tint(.purple)
        .interactive()
)

See Effects for the full configuration API.

How It Works

UniversalGlass uses runtime availability checks to route calls to native SwiftUI APIs on OS 26+ or fall back to material-based approximations on earlier systems. The fallback renderer:

  • Registers effects as participants via anchor preferences
  • Groups views by union keys or effect IDs
  • Draws composite material overlays that respect shapes and transitions

For technical deep dives, see the docs:

Known limitation: On pre-OS 26 systems, the fallback container ignores the spacing parameter.

Contributing

Contributions welcome. Before submitting a PR:

  1. Create an issue outlining the change (optional for small fixes)
  2. Follow the existing Swift formatting and file organisation
  3. Ensure swift build succeeds and add previews/tests where relevant

License

MIT. See LICENSE for details.

About

Bring SwiftUI’s iOS 26 glass APIs to earlier deployments with lightweight shims—keep your UI consistent on iOS 18+, and automatically defer to the real implementations wherever they exist.

Resources

Stars

Watchers

Forks

Sponsor this project

 

Packages

No packages published

Contributors 2

  •  
  •  

Languages