All skills
rshankras avatar

/ui-review-tahoe

@32566aa

Comprehensive UI/UX review for macOS Tahoe apps. Covers Liquid Glass design, HIG compliance, SwiftUI patterns, and accessibility. Use when reviewing macOS UI or checking HIG compliance.

Use this Skill: https://skilld.dev/gh/rshankras/claude-code-apple-skills/ui-review-tahoe

This session only. Nothing lands on disk.

swiftui-macos.md

≈2.6k tokens on demand. Your agent reads this file only when SKILL.md points to it.

SwiftUI for macOS Best Practices

macOS-specific SwiftUI patterns, modifiers, and known Tahoe issues.

macOS-Specific Views

NavigationSplitView

// ✅ GOOD: Sidebar layout for macOS
struct ContentView: View {
    @State private var selection: Item?

    var body: some View {
        NavigationSplitView {
            // Sidebar
            List(items, selection: $selection) { item in
                NavigationLink(value: item) {
                    Label(item.name, systemImage: item.icon)
                }
            }
            .navigationSplitViewColumnWidth(min: 200, ideal: 250, max: 300)
        } detail: {
            // Detail
            if let item = selection {
                ItemDetailView(item: item)
            } else {
                ContentUnavailableView("Select an Item", systemImage: "doc")
            }
        }
        .navigationSplitViewStyle(.balanced)
    }
}

Table View

// ✅ GOOD: Native Table view
struct DocumentsTable: View {
    @State private var documents: [Document]
    @State private var selection = Set<Document.ID>()
    @State private var sortOrder = [KeyPathComparator(\Document.name)]

    var body: some View {
        Table(documents, selection: $selection, sortOrder: $sortOrder) {
            TableColumn("Name", value: \.name) { document in
                HStack {
                    Image(systemName: document.icon)
                    Text(document.name)
                }
            }

            TableColumn("Modified", value: \.modifiedDate) { document in
                Text(document.modifiedDate, style: .date)
            }
            .width(min: 100, ideal: 150)

            TableColumn("Size", value: \.size) { document in
                Text(document.size, format: .byteCount(style: .file))
            }
            .width(ideal: 100)
        }
        .onChange(of: sortOrder) {
            documents.sort(using: sortOrder)
        }
    }
}

macOS-Specific Modifiers

Context Menus

// ✅ GOOD: Rich context menus
.contextMenu {
    Button("Open") {
        openItem()
    }
    Button("Open in New Window") {
        openInNewWindow()
    }

    Divider()

    Button("Rename") {
        startRename()
    }
    Button("Duplicate") {
        duplicateItem()
    }

    Divider()

    Menu("Share") {
        ShareLink(item: shareableItem)
    }

    Divider()

    Button("Delete", role: .destructive) {
        deleteItem()
    }
}

Help Tags (Tooltips)

// ✅ GOOD: Helpful tooltips
Button(action: save) {
    Image(systemName: "square.and.arrow.down")
}
.help("Save document")  // Tooltip on hover

Toggle("Enable feature", isOn: $isEnabled)
    .help("This feature improves performance by...")

Focus Management

// ✅ GOOD: Keyboard focus handling
struct LoginView: View {
    @FocusState private var focusedField: Field?

    enum Field: Hashable {
        case username
        case password
    }

    var body: some View {
        Form {
            TextField("Username", text: $username)
                .focused($focusedField, equals: .username)

            SecureField("Password", text: $password)
                .focused($focusedField, equals: .password)
                .onSubmit {
                    login()
                }
        }
        .onAppear {
            focusedField = .username
        }
    }
}

Known macOS Tahoe SwiftUI Issues

Layout Bugs

// ⚠️ ISSUE: SwiftUI layout broken in some cases on Tahoe
// Workaround: Use explicit frames and spacing

// ❌ May break on Tahoe
VStack {
    Text("Title")
    Text("Subtitle")
}
.frame(maxWidth: .infinity)

// ✅ WORKAROUND: Be explicit
VStack(spacing: 8) {
    Text("Title")
        .frame(maxWidth: .infinity, alignment: .leading)
    Text("Subtitle")
        .frame(maxWidth: .infinity, alignment: .leading)
}
.fixedSize(horizontal: false, vertical: true)

NSHostingView Animation Issues

// ⚠️ ISSUE: Frame changes don't animate smoothly in NSHostingView
// Workaround: Use explicit animation timing

// ❌ May not animate smoothly
.frame(width: isExpanded ? 300 : 100)
.animation(.default, value: isExpanded)

// ✅ WORKAROUND: Use specific timing
.frame(width: isExpanded ? 300 : 100)
.animation(.easeInOut(duration: 0.2), value: isExpanded)

// Or avoid NSHostingView for animated content
// Use pure SwiftUI windows instead

Transparency Issues

// ⚠️ ISSUE: Some transparency effects may not render correctly
// Workaround: Test on actual macOS Tahoe

// ✅ GOOD: Use tested materials
.background(.regularMaterial)
.background(.ultraThinMaterial)

// ⚠️ Test custom transparency
.background(Color.white.opacity(0.5))  // May not work as expected

Window Management

Custom Windows

// ✅ GOOD: Create auxiliary windows
@main
struct MyApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }

        // Inspector window
        Window("Inspector", id: "inspector") {
            InspectorView()
        }
        .defaultSize(width: 300, height: 600)
        .windowResizability(.contentSize)

        // Preferences
        Settings {
            SettingsView()
        }
    }
}

// Open window from code
@Environment(\.openWindow) var openWindow

Button("Show Inspector") {
    openWindow(id: "inspector")
}

Window Toolbar Customization

// ✅ GOOD: Unified toolbar style
.windowStyle(.hiddenTitleBar)
.windowToolbarStyle(.unified)

// ✅ GOOD: Expanded toolbar
.windowToolbarStyle(.expanded)

// ✅ GOOD: Automatic based on content
.windowToolbarStyle(.automatic)

Menus and Commands

MenuBarExtra

// ✅ GOOD: Menu bar app
@main
struct MenuBarApp: App {
    var body: some Scene {
        MenuBarExtra("My App", systemImage: "star.fill") {
            Button("Action 1") {
                // Action
            }

            Button("Action 2") {
                // Action
            }

            Divider()

            Button("Quit") {
                NSApplication.shared.terminate(nil)
            }
            .keyboardShortcut("q")
        }
    }
}

Context Menu for Menu Bar

// ✅ GOOD: Menu bar extra with label
MenuBarExtra("Status", systemImage: statusIcon) {
    VStack {
        Text("Status: \(currentStatus)")
        Divider()
        Button("Refresh") {
            refresh()
        }
    }
}
.menuBarExtraStyle(.window)  // Shows as popover

Observation Framework

Using @Observable (macOS 14+)

// ✅ GOOD: New Observation framework
import Observation

@Observable
final class ArticleViewModel {
    var articles: [Article] = []
    var isLoading = false
    var error: Error?

    func loadArticles() async {
        isLoading = true
        // Load articles...
        isLoading = false
    }
}

// Usage in view - automatic updates
struct ArticleListView: View {
    let viewModel: ArticleViewModel

    var body: some View {
        List(viewModel.articles) { article in
            Text(article.title)
        }
        .overlay {
            if viewModel.isLoading {
                ProgressView()
            }
        }
        .task {
            await viewModel.loadArticles()
        }
    }
}

// ❌ OLD: ObservableObject (still works, but @Observable is preferred)
class ArticleViewModel: ObservableObject {
    @Published var articles: [Article] = []
}

Gestures and Interactions

Mouse Events

// ✅ GOOD: Hover effects
.onHover { isHovered in
    withAnimation {
        self.isHovered = isHovered
    }
}
.scaleEffect(isHovered ? 1.05 : 1.0)

// ✅ GOOD: Right-click handling
.onTapGesture(count: 1, perform: leftClick)
.gesture(
    TapGesture(count: 1)
        .modifiers(.control)
        .onEnded { _ in
            showContextMenu()
        }
)

Drag and Drop

// ✅ GOOD: Draggable items
Text(item.name)
    .draggable(item)

// ✅ GOOD: Drop destination
List {
    // Items
}
.dropDestination(for: Item.self) { items, location in
    handleDrop(items, at: location)
    return true
}

Performance Optimization

LazyVStack vs VStack

// ✅ GOOD: Use LazyVStack for long lists
ScrollView {
    LazyVStack(spacing: 8) {
        ForEach(items) { item in
            ItemRow(item: item)
        }
    }
}

// ❌ BAD: Regular VStack loads all items
ScrollView {
    VStack {
        ForEach(items) { item in  // Loads everything!
            ItemRow(item: item)
        }
    }
}

Drawing Performance

// ✅ GOOD: Use drawingGroup for complex graphics
Canvas { context, size in
    // Complex drawing
}
.drawingGroup()  // Offloads to Metal

// ✅ GOOD: Cache expensive calculations
.backgroundStyle(
    LinearGradient(...)
        .drawingGroup()
)

SwiftUI + AppKit Bridge

NSViewRepresentable

// ✅ GOOD: Wrap NSTextField for advanced features
struct AdvancedTextField: NSViewRepresentable {
    @Binding var text: String

    func makeNSView(context: Context) -> NSTextField {
        let textField = NSTextField()
        textField.delegate = context.coordinator
        return textField
    }

    func updateNSView(_ nsView: NSTextField, context: Context) {
        nsView.stringValue = text
    }

    func makeCoordinator() -> Coordinator {
        Coordinator(text: $text)
    }

    class Coordinator: NSObject, NSTextFieldDelegate {
        @Binding var text: String

        init(text: Binding<String>) {
            _text = text
        }

        func controlTextDidChange(_ notification: Notification) {
            if let textField = notification.object as? NSTextField {
                text = textField.stringValue
            }
        }
    }
}

SwiftUI Checklist for macOS

  • Use NavigationSplitView for sidebar layouts
  • Use Table for tabular data
  • Provide rich context menus
  • Add help tags (tooltips) to controls
  • Manage keyboard focus appropriately
  • Use @Observable for view models (macOS 14+)
  • Handle hover interactions
  • Support drag and drop where appropriate
  • Use LazyVStack for long lists
  • Test layout on actual macOS Tahoe
  • Verify animations in NSHostingView
  • Use proper window toolbar styles

Resources

Source: SKILL.md on GitHub

No alerts2mo3 checks · Risk SAFE
  • Gen Agent Trust Hub2mo

    The skill is a set of instructional documents and guidance for performing UI/UX reviews of macOS applications. It contains no malicious code, obfuscation, or data exfiltration patterns, and is focused entirely on providing design feedback based on Apple's guidelines.

  • Socket2mo

    No alerts

  • Snyk2mo

    Risk: LOW · No issues

Signed by skilld at 32566aa. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 2 months ago.

Steadyupdated 3 months ago
What it can do
Reads files Network
last_verified
2026-07-16
review_by
2027-06-22
os_version
iOS 27 / macOS 27
All 4 allowed tools
ReadGlobGrepWebFetch

README badge

README badge for rshankras/claude-code-apple-skills/ui-review-tahoe