Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
rshankras avatar

Liquid Glass

  • 4 installs
  • 591 repo stars
  • Updated July 24, 2026
  • rshankras/claude-code-apple-skills

Helps with ai & agent building tasks.

About

liquid-glass is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.

  • liquid-glass
  • AI & Agent Building
  • AI-coding skill

Liquid Glass by the numbers

  • 4 all-time installs (skills.sh)
  • Ranked #13,348 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/rshankras/claude-code-apple-skills --skill liquid-glass

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs4
repo stars591
Last updatedJuly 24, 2026
Repositoryrshankras/claude-code-apple-skills

What it does

Helps with ai & agent building tasks.

Files

SKILL.mdMarkdownGitHub ↗

Liquid Glass Design

Implement Apple's Liquid Glass design language across all Apple UI frameworks. Covers SwiftUI (.glassEffect()), AppKit (NSGlassEffectView), UIKit (UIGlassEffect + UIVisualEffectView), and WidgetKit (rendering modes, accented content, glass elements in widgets).

When This Skill Activates

  • User wants glass/blur effects on views
  • User asks about Liquid Glass or modern Apple design
  • User needs transparent, interactive UI elements
  • User wants morphing transitions between views
  • User is implementing glass effects in UIKit with UIVisualEffectView
  • User needs UIGlassEffect or UIGlassContainerEffect
  • User asks about scroll view edge effects in UIKit
  • User wants Liquid Glass in widgets (WidgetKit)
  • User needs to support accented rendering mode in widgets
  • User asks about widget textures or mounting styles on visionOS

Quick Start (SwiftUI)

Basic Glass Effect

import SwiftUI

Text("Hello, World!")
    .font(.title)
    .padding()
    .glassEffect()  // Capsule shape by default

Custom Shape

Text("Hello")
    .padding()
    .glassEffect(in: .rect(cornerRadius: 16))

// Available shapes:
// .capsule (default)
// .rect(cornerRadius: CGFloat)
// .circle

Interactive Glass

Button("Tap Me") {
    // action
}
.padding()
.glassEffect(.regular.interactive())

Tinted Glass

Text("Important")
    .padding()
    .glassEffect(.regular.tint(.blue))

Glass Configuration Options

OptionDescriptionExample
.regularStandard glass effect.glassEffect(.regular)
.tint(Color)Add color tint.glassEffect(.regular.tint(.orange))
.interactive()React to touch/hover.glassEffect(.regular.interactive())

Multiple Glass Effects

GlassEffectContainer

When using multiple glass elements, wrap them in GlassEffectContainer for:

  • Better rendering performance
  • Proper blending between effects
  • Morphing transitions
GlassEffectContainer(spacing: 40.0) {
    HStack(spacing: 40.0) {
        Image(systemName: "star.fill")
            .frame(width: 80, height: 80)
            .font(.system(size: 36))
            .glassEffect()

        Image(systemName: "heart.fill")
            .frame(width: 80, height: 80)
            .font(.system(size: 36))
            .glassEffect()
    }
}

Spacing Parameter:

  • Controls when effects merge
  • Smaller spacing = views must be closer to merge
  • Larger spacing = effects merge at greater distances

Uniting Glass Effects

Combine views into a single glass effect using glassEffectUnion:

@Namespace private var namespace

GlassEffectContainer(spacing: 20.0) {
    HStack(spacing: 20.0) {
        ForEach(items.indices, id: \.self) { index in
            Image(systemName: items[index])
                .frame(width: 60, height: 60)
                .glassEffect()
                .glassEffectUnion(
                    id: index < 2 ? "group1" : "group2",
                    namespace: namespace
                )
        }
    }
}

Morphing Transitions

Create fluid morphing effects when views appear/disappear.

Setup

1. Create a namespace 2. Assign glass effect IDs 3. Use animations on state changes

struct MorphingToolbar: View {
    @State private var isExpanded = false
    @Namespace private var namespace

    var body: some View {
        GlassEffectContainer(spacing: 40.0) {
            HStack(spacing: 40.0) {
                // Always visible
                Image(systemName: "pencil")
                    .frame(width: 60, height: 60)
                    .glassEffect()
                    .glassEffectID("pencil", in: namespace)

                // Conditionally visible - will morph in/out
                if isExpanded {
                    Image(systemName: "eraser")
                        .frame(width: 60, height: 60)
                        .glassEffect()
                        .glassEffectID("eraser", in: namespace)

                    Image(systemName: "ruler")
                        .frame(width: 60, height: 60)
                        .glassEffect()
                        .glassEffectID("ruler", in: namespace)
                }
            }
        }

        Button("Toggle") {
            withAnimation(.spring(response: 0.4, dampingFraction: 0.8)) {
                isExpanded.toggle()
            }
        }
        .buttonStyle(.glass)
    }
}

Button Styles

Glass Button

Button("Standard") {
    // action
}
.buttonStyle(.glass)

Glass Prominent Button

Button("Primary Action") {
    // action
}
.buttonStyle(.glassProminent)

Advanced Techniques

Background Extension

Stretch content under sidebar or inspector:

NavigationSplitView {
    SidebarView()
} detail: {
    DetailView()
        .background {
            Image("wallpaper")
                .resizable()
                .ignoresSafeArea()
        }
}

Horizontal Scroll Under Sidebar

ScrollView(.horizontal) {
    HStack {
        ForEach(items) { item in
            ItemView(item: item)
        }
    }
}
.scrollExtensionMode(.underSidebar)

AppKit Implementation

NSGlassEffectView

import AppKit

// Create glass effect view
let glassView = NSGlassEffectView(frame: NSRect(x: 20, y: 20, width: 200, height: 100))
glassView.cornerRadius = 16.0
glassView.tintColor = NSColor.systemBlue.withAlphaComponent(0.3)

// Create content
let label = NSTextField(labelWithString: "Glass Content")
label.translatesAutoresizingMaskIntoConstraints = false

// Set content view
glassView.contentView = label

// Add constraints
if let contentView = glassView.contentView {
    NSLayoutConstraint.activate([
        label.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
        label.centerYAnchor.constraint(equalTo: contentView.centerYAnchor)
    ])
}

NSGlassEffectContainerView

// Create container
let container = NSGlassEffectContainerView(frame: bounds)
container.spacing = 40.0

// Create content view
let contentView = NSView(frame: container.bounds)
container.contentView = contentView

// Add glass views to content
let glass1 = NSGlassEffectView(frame: NSRect(x: 20, y: 50, width: 150, height: 100))
let glass2 = NSGlassEffectView(frame: NSRect(x: 190, y: 50, width: 150, height: 100))

contentView.addSubview(glass1)
contentView.addSubview(glass2)

Interactive AppKit Glass

class InteractiveGlassView: NSGlassEffectView {
    override init(frame: NSRect) {
        super.init(frame: frame)
        setupTracking()
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupTracking()
    }

    private func setupTracking() {
        let options: NSTrackingArea.Options = [
            .mouseEnteredAndExited,
            .activeInActiveApp
        ]
        let trackingArea = NSTrackingArea(
            rect: bounds,
            options: options,
            owner: self,
            userInfo: nil
        )
        addTrackingArea(trackingArea)
    }

    override func mouseEntered(with event: NSEvent) {
        super.mouseEntered(with: event)
        NSAnimationContext.runAnimationGroup { context in
            context.duration = 0.2
            animator().tintColor = NSColor.systemBlue.withAlphaComponent(0.2)
        }
    }

    override func mouseExited(with event: NSEvent) {
        super.mouseExited(with: event)
        NSAnimationContext.runAnimationGroup { context in
            context.duration = 0.2
            animator().tintColor = nil
        }
    }
}

Common Patterns

Floating Action Bar

struct FloatingActionBar: View {
    @Namespace private var namespace

    var body: some View {
        GlassEffectContainer(spacing: 20) {
            HStack(spacing: 16) {
                ForEach(actions) { action in
                    Button {
                        action.perform()
                    } label: {
                        Image(systemName: action.icon)
                            .font(.title2)
                    }
                    .frame(width: 44, height: 44)
                    .glassEffect(.regular.interactive())
                    .glassEffectID(action.id, in: namespace)
                }
            }
            .padding(.horizontal, 8)
            .padding(.vertical, 4)
        }
    }
}

Card with Glass Effect

struct GlassCard: View {
    let title: String
    let subtitle: String
    let icon: String

    var body: some View {
        HStack(spacing: 16) {
            Image(systemName: icon)
                .font(.title)
                .frame(width: 50, height: 50)
                .glassEffect(.regular.tint(.blue))

            VStack(alignment: .leading) {
                Text(title)
                    .font(.headline)
                Text(subtitle)
                    .font(.subheadline)
                    .foregroundStyle(.secondary)
            }

            Spacer()
        }
        .padding()
        .glassEffect(in: .rect(cornerRadius: 16))
    }
}

Tab Bar with Morphing

struct GlassTabBar: View {
    @Binding var selection: Int
    @Namespace private var namespace

    let tabs = [
        ("house", "Home"),
        ("magnifyingglass", "Search"),
        ("person", "Profile")
    ]

    var body: some View {
        GlassEffectContainer(spacing: 30) {
            HStack(spacing: 30) {
                ForEach(tabs.indices, id: \.self) { index in
                    Button {
                        withAnimation(.spring(response: 0.35, dampingFraction: 0.8)) {
                            selection = index
                        }
                    } label: {
                        VStack(spacing: 4) {
                            Image(systemName: tabs[index].0)
                                .font(.title2)
                            Text(tabs[index].1)
                                .font(.caption)
                        }
                        .frame(width: 70, height: 60)
                    }
                    .glassEffect(
                        selection == index
                            ? .regular.tint(.blue).interactive()
                            : .regular.interactive()
                    )
                    .glassEffectID("tab\(index)", in: namespace)
                }
            }
        }
    }
}

Migration from Old API

Before (Old Approach)

// Old: Using materials directly
VStack {
    Text("Content")
}
.padding()
.background(.ultraThinMaterial)
.cornerRadius(16)

After (New API)

// New: Using glassEffect modifier
VStack {
    Text("Content")
}
.padding()
.glassEffect(in: .rect(cornerRadius: 16))

Key Differences

Old ApproachNew API
.background(.material).glassEffect()
Manual corner radiusShape parameter
No interactivity.interactive() modifier
Manual tinting.tint(Color) modifier
No morphingglassEffectID + @Namespace
No container groupingGlassEffectContainer

UIKit Implementation

UIGlassEffect

Use UIVisualEffectView with a UIGlassEffect to create glass surfaces in UIKit:

import UIKit

let glassEffect = UIGlassEffect()
let visualEffectView = UIVisualEffectView(effect: glassEffect)
visualEffectView.frame = CGRect(x: 50, y: 100, width: 300, height: 200)
visualEffectView.layer.cornerRadius = 20
visualEffectView.clipsToBounds = true

let label = UILabel()
label.text = "Liquid Glass"
label.textAlignment = .center
label.frame = visualEffectView.bounds
visualEffectView.contentView.addSubview(label)
view.addSubview(visualEffectView)
Customizing the Glass Effect
glassEffect.tintColor = UIColor.systemBlue.withAlphaComponent(0.3)
glassEffect.isInteractive = true

Interactive Glass in UIKit

Set isInteractive = true on a UIGlassEffect to make it respond to touch:

let interactiveGlassEffect = UIGlassEffect()
interactiveGlassEffect.isInteractive = true

let glassButton = UIButton(frame: CGRect(x: 50, y: 300, width: 200, height: 50))
glassButton.setTitle("Glass Button", for: .normal)
glassButton.setTitleColor(.white, for: .normal)

let buttonEffectView = UIVisualEffectView(effect: interactiveGlassEffect)
buttonEffectView.frame = glassButton.bounds
buttonEffectView.layer.cornerRadius = 15
buttonEffectView.clipsToBounds = true

glassButton.insertSubview(buttonEffectView, at: 0)
view.addSubview(glassButton)

UIGlassContainerEffect

Use UIGlassContainerEffect when combining multiple glass elements. This is the UIKit equivalent of SwiftUI's GlassEffectContainer -- it enables proper blending and morphing between glass views:

let containerEffect = UIGlassContainerEffect()
containerEffect.spacing = 40.0

let containerView = UIVisualEffectView(effect: containerEffect)
containerView.frame = CGRect(x: 50, y: 400, width: 300, height: 200)

let firstGlassEffect = UIGlassEffect()
let firstGlassView = UIVisualEffectView(effect: firstGlassEffect)
firstGlassView.frame = CGRect(x: 20, y: 20, width: 100, height: 100)
firstGlassView.layer.cornerRadius = 20
firstGlassView.clipsToBounds = true

let secondGlassEffect = UIGlassEffect()
secondGlassEffect.tintColor = UIColor.systemPink.withAlphaComponent(0.3)
let secondGlassView = UIVisualEffectView(effect: secondGlassEffect)
secondGlassView.frame = CGRect(x: 80, y: 60, width: 100, height: 100)
secondGlassView.layer.cornerRadius = 20
secondGlassView.clipsToBounds = true

containerView.contentView.addSubview(firstGlassView)
containerView.contentView.addSubview(secondGlassView)
view.addSubview(containerView)

Scroll View Edge Effects

UIKit scroll views now support configurable edge effects for Liquid Glass integration:

let scrollView = UIScrollView(frame: view.bounds)
scrollView.topEdgeEffect.style = .automatic
scrollView.bottomEdgeEffect.style = .hard
scrollView.leftEdgeEffect.isHidden = true
scrollView.rightEdgeEffect.isHidden = true

Available Edge Effect Styles:

StyleDescription
.automaticSystem determines style based on context
.hardHard cutoff with a dividing line

UIScrollEdgeElementContainerInteraction

Use UIScrollEdgeElementContainerInteraction to coordinate glass elements (such as bottom toolbars) with scroll edge behavior:

let interaction = UIScrollEdgeElementContainerInteraction()
interaction.scrollView = scrollView
interaction.edge = .bottom
buttonContainer.addInteraction(interaction)

Toolbar Integration

UIKit navigation bar items integrate with Liquid Glass automatically. Use hidesSharedBackground to opt individual items out of the shared glass bar:

let shareButton = UIBarButtonItem(
    barButtonSystemItem: .action,
    target: self,
    action: #selector(shareAction)
)
let favoriteButton = UIBarButtonItem(
    image: UIImage(systemName: "heart"),
    style: .plain,
    target: self,
    action: #selector(favoriteAction)
)
favoriteButton.hidesSharedBackground = true
navigationItem.rightBarButtonItems = [shareButton, favoriteButton]

UIKit vs SwiftUI Comparison

SwiftUIUIKit
.glassEffect()UIVisualEffectView(effect: UIGlassEffect())
.glassEffect(.regular.interactive())UIGlassEffect() with isInteractive = true
.glassEffect(.regular.tint(.blue))UIGlassEffect() with tintColor = ...
GlassEffectContainer(spacing:)UIGlassContainerEffect() with spacing
.buttonStyle(.glass)Insert UIVisualEffectView as button subview

WidgetKit Implementation

Rendering Modes

Widgets support two rendering modes that affect how Liquid Glass is displayed:

ModeDescription
Full ColorDefault mode. Displays all colors, images, and transparency as designed.
AccentedUsed when tinted or clear appearance is chosen. Primary and accented content tinted white (iOS and macOS). Background replaced with themed glass or tinted color effect.

Accented Mode

Detect the rendering mode and adapt layout accordingly. Use .widgetAccentable() to mark views that should be tinted in accented mode:

struct MyWidgetView: View {
    @Environment(\.widgetRenderingMode) var renderingMode

    var body: some View {
        if renderingMode == .accented {
            // Layout optimized for accented mode
            AccentedWidgetLayout()
        } else {
            // Standard full-color layout
            FullColorWidgetLayout()
        }
    }
}
Grouping Accent Content
HStack(alignment: .center, spacing: 0) {
    VStack(alignment: .leading) {
        Text("Widget Title")
            .font(.headline)
            .widgetAccentable()
        Text("Widget Subtitle")
    }
    Image(systemName: "star.fill")
        .widgetAccentable()
}
Image Rendering in Accented Mode
Image("myImage")
    .widgetAccentedRenderingMode(.monochrome)

Container Backgrounds

Define a container background for your widget content:

var body: some View {
    VStack {
        // Widget content
    }
    .containerBackground(for: .widget) {
        Color.blue.opacity(0.2)
    }
}

Background Removal

Prevent the system from removing the widget background. Note that marking a background as non-removable excludes the widget from contexts that require removable backgrounds (iPad Lock Screen, StandBy):

var body: some WidgetConfiguration {
    StaticConfiguration(kind: "MyWidget", provider: Provider()) { entry in
        MyWidgetView(entry: entry)
    }
    .containerBackgroundRemovable(false)
}

visionOS Textures and Mounting Styles

Widget Textures
// Default glass texture
.widgetTexture(.glass)

// Paper-like texture
.widgetTexture(.paper)
Mounting Styles
.supportedMountingStyles([.recessed, .elevated])
StyleDescription
.recessedWidget appears embedded into a vertical surface
.elevatedWidget appears on top of a surface

Custom Glass Elements in Widgets

Apply .glassEffect() and .buttonStyle(.glass) directly within widget views:

// Glass text element
Text("Custom Element")
    .padding()
    .glassEffect()

// Glass image element
Image(systemName: "star.fill")
    .frame(width: 60, height: 60)
    .glassEffect(.regular, in: .rect(cornerRadius: 12))

// Glass button in widget
Button("Action") { }
    .buttonStyle(.glass)

Best Practices

1. Use GlassEffectContainer for multiple glass views

  • Improves rendering performance
  • Enables morphing transitions

2. Apply glass effect last in modifier chain

  • After frame, padding, and content modifiers

3. Choose appropriate spacing in containers

  • Controls when effects blend together

4. Use animations for state changes

  • Enables smooth morphing transitions

5. Add interactivity for touchable elements

  • .interactive() for buttons and controls

6. Tint strategically to indicate state

  • Selected items, primary actions

7. Consistent shapes across your app

  • Establish a shape language (all capsules, or all rounded rects)

Checklist

SwiftUI

  • [ ] Use .glassEffect() instead of .background(.material)
  • [ ] Wrap multiple glass views in GlassEffectContainer
  • [ ] Add @Namespace for morphing transitions
  • [ ] Use .glassEffectID() on views that appear/disappear
  • [ ] Add .interactive() for touchable elements
  • [ ] Use .buttonStyle(.glass) for glass buttons
  • [ ] Test animations for smooth morphing

UIKit

  • [ ] Use UIVisualEffectView with UIGlassEffect for glass surfaces
  • [ ] Set isInteractive = true on glass effects for touchable elements
  • [ ] Wrap multiple glass views in UIGlassContainerEffect
  • [ ] Configure scroll view edge effects (.automatic or .hard)
  • [ ] Use UIScrollEdgeElementContainerInteraction for scroll-coordinated toolbars
  • [ ] Use hidesSharedBackground for toolbar items that need independent glass

WidgetKit

  • [ ] Detect widgetRenderingMode and adapt layout for accented mode
  • [ ] Mark accent content with .widgetAccentable()
  • [ ] Set .widgetAccentedRenderingMode() on images
  • [ ] Define .containerBackground(for: .widget) for backgrounds
  • [ ] Use .containerBackgroundRemovable(false) only when necessary
  • [ ] Apply .glassEffect() and .buttonStyle(.glass) in widget views
  • [ ] Configure .widgetTexture() and .supportedMountingStyles() for visionOS

General

  • [ ] Consider performance with many glass effects
  • [ ] Support both light and dark appearances

References

SwiftUI

AppKit

UIKit

WidgetKit

Related skills

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.