All skills

Comprehensive macOS development guidance including Swift 6+, SwiftUI, SwiftData, architecture patterns, AppKit bridging, and macOS 26 Tahoe APIs. Use for macOS code review, best practices, UI review, or platform-specific features.

  • 40 files
  • 300.9 KB
  • Updated 3 months ago
  • GitHub

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

This session only. Nothing lands on disk.

ui-review-tahoeappkit-modern.md

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

Modern AppKit Patterns

AppKit best practices for macOS 26 (Tahoe) with Liquid Glass design integration.

When to Use AppKit

  • Complex table views with custom cells
  • Advanced text editing (NSTextView)
  • Custom drawing with precise control
  • Legacy code migration
  • Features not yet available in SwiftUI
  • Performance-critical UI components

Modern NSViewController Patterns

// ✅ GOOD: Modern view controller
final class ArticleViewController: NSViewController {
    // MARK: - Properties
    private let viewModel: ArticleViewModel
    private var cancellables = Set<AnyCancellable>()

    // MARK: - UI Elements
    private lazy var tableView: NSTableView = {
        let table = NSTableView()
        table.delegate = self
        table.dataSource = self
        table.style = .automatic
        return table
    }()

    // MARK: - Initialization
    init(viewModel: ArticleViewModel) {
        self.viewModel = viewModel
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) not implemented")
    }

    // MARK: - Lifecycle
    override func loadView() {
        view = NSView()
        setupUI()
        setupConstraints()
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        bindViewModel()
    }

    // MARK: - Setup
    private func setupUI() {
        // Setup UI elements
    }

    private func setupConstraints() {
        // Use Auto Layout
        tableView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: view.topAnchor),
            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
    }

    private func bindViewModel() {
        viewModel.$articles
            .sink { [weak self] _ in
                self?.tableView.reloadData()
            }
            .store(in: &cancellables)
    }
}

Liquid Glass in AppKit

Visual Effect Views

// ✅ GOOD: Use NSVisualEffectView for Liquid Glass
final class GlassPanel: NSView {
    private let visualEffectView: NSVisualEffectView = {
        let view = NSVisualEffectView()
        view.material = .sidebar
        view.blendingMode = .behindWindow
        view.state = .active
        return view
    }()

    override init(frame: NSRect) {
        super.init(frame: frame)
        setup()
    }

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

    private func setup() {
        addSubview(visualEffectView)
        visualEffectView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            visualEffectView.topAnchor.constraint(equalTo: topAnchor),
            visualEffectView.leadingAnchor.constraint(equalTo: leadingAnchor),
            visualEffectView.trailingAnchor.constraint(equalTo: trailingAnchor),
            visualEffectView.bottomAnchor.constraint(equalTo: bottomAnchor)
        ])

        // Round corners
        wantsLayer = true
        layer?.cornerRadius = 12
        layer?.masksToBounds = true
    }
}

Transparent Window Background

// ✅ GOOD: Window with transparency
final class TransparentWindow: NSWindow {
    override init(
        contentRect: NSRect,
        styleMask style: NSWindow.StyleMask,
        backing backingStoreType: NSWindow.BackingStoreType,
        defer flag: Bool
    ) {
        super.init(
            contentRect: contentRect,
            styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
            backing: backingStoreType,
            defer: flag
        )

        titlebarAppearsTransparent = true
        titleVisibility = .hidden
        isOpaque = false
        backgroundColor = .clear

        // Modern appearance
        if let contentView = contentView {
            let visualEffect = NSVisualEffectView()
            visualEffect.material = .underWindowBackground
            visualEffect.blendingMode = .behindWindow
            visualEffect.state = .active
            visualEffect.frame = contentView.bounds
            visualEffect.autoresizingMask = [.width, .height]
            contentView.addSubview(visualEffect, positioned: .below, relativeTo: nil)
        }
    }
}

Modern Table Views

// ✅ GOOD: Cell-based table view
extension ArticleViewController: NSTableViewDataSource {
    func numberOfRows(in tableView: NSTableView) -> Int {
        viewModel.articles.count
    }
}

extension ArticleViewController: NSTableViewDelegate {
    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
        let article = viewModel.articles[row]

        guard let cellView = tableView.makeView(
            withIdentifier: ArticleCellView.identifier,
            owner: self
        ) as? ArticleCellView else {
            let cellView = ArticleCellView()
            cellView.identifier = ArticleCellView.identifier
            return cellView
        }

        cellView.configure(with: article)
        return cellView
    }

    func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
        60
    }
}

// ✅ GOOD: Custom cell view
final class ArticleCellView: NSTableCellView {
    static let identifier = NSUserInterfaceItemIdentifier("ArticleCell")

    private let titleLabel: NSTextField = {
        let label = NSTextField(labelWithString: "")
        label.font = .systemFont(ofSize: 14, weight: .medium)
        label.lineBreakMode = .byTruncatingTail
        return label
    }()

    private let subtitleLabel: NSTextField = {
        let label = NSTextField(labelWithString: "")
        label.font = .systemFont(ofSize: 12)
        label.textColor = .secondaryLabelColor
        return label
    }()

    override init(frame: NSRect) {
        super.init(frame: frame)
        setup()
    }

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

    private func setup() {
        // Add subviews and constraints
    }

    func configure(with article: Article) {
        titleLabel.stringValue = article.title
        subtitleLabel.stringValue = article.subtitle
    }
}

Window Management

// ✅ GOOD: Modern window controller
final class DocumentWindowController: NSWindowController {
    convenience init() {
        let window = NSWindow(
            contentRect: NSRect(x: 0, y: 0, width: 800, height: 600),
            styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
            backing: .buffered,
            defer: false
        )

        window.center()
        window.titlebarAppearsTransparent = true
        window.titleVisibility = .hidden

        self.init(window: window)
    }

    override func windowDidLoad() {
        super.windowDidLoad()

        // Setup toolbar
        let toolbar = NSToolbar(identifier: "MainToolbar")
        toolbar.delegate = self
        toolbar.displayMode = .iconOnly
        window?.toolbar = toolbar
    }
}

extension DocumentWindowController: NSToolbarDelegate {
    func toolbar(
        _ toolbar: NSToolbar,
        itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier,
        willBeInsertedIntoToolbar flag: Bool
    ) -> NSToolbarItem? {
        // Return toolbar items
    }

    func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
        [.flexibleSpace, .add, .share]
    }
}

Split View Controllers

// ✅ GOOD: Modern split view
final class MainSplitViewController: NSSplitViewController {
    private let sidebarViewController: SidebarViewController
    private let detailViewController: DetailViewController

    init(
        sidebarViewController: SidebarViewController,
        detailViewController: DetailViewController
    ) {
        self.sidebarViewController = sidebarViewController
        self.detailViewController = detailViewController
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) not implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // Sidebar item
        let sidebarItem = NSSplitViewItem(sidebarWithViewController: sidebarViewController)
        sidebarItem.minimumThickness = 200
        sidebarItem.maximumThickness = 300
        addSplitViewItem(sidebarItem)

        // Detail item
        let detailItem = NSSplitViewItem(viewController: detailViewController)
        addSplitViewItem(detailItem)

        splitView.autosaveName = "MainSplitView"
    }
}

Menu Bar Apps with AppKit

// ✅ GOOD: Modern menu bar app
@main
class AppDelegate: NSObject, NSApplicationDelegate {
    private var statusItem: NSStatusItem?
    private var popover: NSPopover?

    func applicationDidFinishLaunching(_ notification: Notification) {
        // Create status item
        statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.squareLength)

        if let button = statusItem?.button {
            button.image = NSImage(systemSymbolName: "star.fill", accessibilityDescription: "App")
            button.action = #selector(togglePopover)
        }

        // Create popover
        let popover = NSPopover()
        popover.contentViewController = MenuViewController()
        popover.behavior = .transient
        self.popover = popover
    }

    @objc private func togglePopover() {
        guard let button = statusItem?.button else { return }

        if let popover = popover {
            if popover.isShown {
                popover.performClose(nil)
            } else {
                popover.show(relativeTo: button.bounds, of: button, preferredEdge: .minY)
            }
        }
    }
}

Responder Chain and Events

// ✅ GOOD: Handling key events
override func keyDown(with event: NSEvent) {
    switch event.keyCode {
    case 51:  // Delete
        deleteSelected()
    case 36:  // Return
        editSelected()
    default:
        super.keyDown(with: event)
    }
}

// ✅ GOOD: Validating menu items
extension ViewController: NSMenuItemValidation {
    func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
        switch menuItem.action {
        case #selector(delete(_:)):
            return selectedItems.count > 0
        case #selector(duplicate(_:)):
            return selectedItems.count == 1
        default:
            return true
        }
    }
}

Animations in AppKit

// ✅ GOOD: NSAnimationContext
NSAnimationContext.runAnimationGroup { context in
    context.duration = 0.3
    context.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
    view.animator().alphaValue = 0.5
    view.animator().frame = newFrame
}

// ✅ GOOD: Core Animation layers
view.wantsLayer = true
view.layer?.add(animation, forKey: "transform")

AppKit + SwiftUI Integration

// ✅ GOOD: Hosting SwiftUI in AppKit
final class SwiftUIHostingController: NSViewController {
    init() {
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) not implemented")
    }

    override func loadView() {
        let swiftUIView = ContentView()
        let hostingView = NSHostingView(rootView: swiftUIView)
        self.view = hostingView
    }
}

// ✅ GOOD: Embedding AppKit in SwiftUI (see swiftui-macos.md)

Modern AppKit Checklist

  • Use NSVisualEffectView for Liquid Glass effects
  • Implement transparent window backgrounds
  • Use Auto Layout constraints
  • Follow MVVM pattern with ViewModels
  • Use Combine for reactive bindings
  • Implement proper responder chain
  • Support dark mode and accent colors
  • Use NSToolbar for window toolbars
  • Implement NSSplitViewController for sidebars
  • Support keyboard shortcuts and menu validation
  • Use smooth animations
  • Integrate SwiftUI where beneficial

Resources

Source: SKILL.md on GitHub

No third-party reports yet.

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/macos