Skip to content

Instantly share code, notes, and snippets.

@stephancasas
Last active March 3, 2026 10:25
Show Gist options
  • Select an option

  • Save stephancasas/c801e4fa7918067c19bb548520725053 to your computer and use it in GitHub Desktop.

Select an option

Save stephancasas/c801e4fa7918067c19bb548520725053 to your computer and use it in GitHub Desktop.
An extension on `NSAlert` for `NSTextField` drawing/management
//
// NSAlert+NSTextField.swift
//
// Created by Stephan Casas for OpenAI on 2/26/26.
//
import Foundation
import AppKit
extension NSAlert {
// MARK: - NSTextField Additions
/// Create and add a text field to the alert. The text field will become the first responder when the alert is displayed.
/// - Parameters:
/// - title: An optional label string which is drawn above the text field.
/// - placeholder: An optional placeholder string drawn within the text field.
/// - Returns: the added text field instance
@discardableResult
func addTextField(title: String? = nil, placeholder: String? = nil) -> NSTextField? {
let selector = NSSelectorFromString("addTextFieldWithTitle:")
guard
responds(to: selector),
let textField = perform(selector, with: title).takeUnretainedValue() as? NSTextField
else {
return nil
}
textField.placeholderString = placeholder
return textField
}
/// Create and add a secure text field to the alert. The text field will become the first responder when the alert is displayed.
/// - Parameters:
/// - title: An optional label string which is drawn above the text field.
/// - placeholder: An optional placeholder string drawn within the text field.
/// - Returns: the added secure text field instance
@discardableResult
func addSecureTextField(title: String? = nil, placeholder: String? = nil) -> NSSecureTextField? {
let selector = NSSelectorFromString("addSecureTextFieldWithTitle:")
guard
responds(to: selector),
let textField = perform(selector, with: title).takeUnretainedValue() as? NSSecureTextField
else {
return nil
}
textField.placeholderString = placeholder
return textField
}
/// The text fields managed by this alert.
var textFields: [NSTextField] {
let key = "textFields"
return if responds(to: NSSelectorFromString(key)) {
value(forKey: key) as? [NSTextField] ?? []
} else {
[]
}
}
// MARK: - Attributed String Additions
private static let attributedInformativeTextKey = "attributedInformativeText"
private static let attributedInformativeTextSetter = NSSelectorFromString("setAttributedInformativeText:")
/// As an attributed string, the descriptive text that provides more details about the reason for the alert.
var attributedInformativeText: NSAttributedString? {
get {
if responds(to: NSSelectorFromString(Self.attributedInformativeTextKey)) {
value(forKey: Self.attributedInformativeTextKey) as? NSAttributedString
} else {
nil
}
}
set {
if responds(to: Self.attributedInformativeTextSetter) {
setValue(newValue, forKey: Self.attributedInformativeTextKey)
}
}
}
private static let attributedMessageTextKey = "attributedMessageText"
private static let attributedMessageTextSetter = NSSelectorFromString("setAttributedMessageText:")
/// As an attributed string, the text that is displayed prominently in the alert.
var attributedMessageText: NSAttributedString? {
get {
if responds(to: NSSelectorFromString(Self.attributedMessageTextKey)) {
value(forKey: Self.attributedMessageTextKey) as? NSAttributedString
} else {
nil
}
}
set {
if responds(to: Self.attributedMessageTextSetter) {
setValue(newValue, forKey: Self.attributedMessageTextKey)
}
}
}
// MARK: - Convenience
/// Runs the alert modally as a sheet attached to the specified window.
/// - Parameter sheetWindow: The window on which to display the sheet.
/// - Returns: A tuple value containing both the modal response and an ordered array of strings for each alert-managed text field.
@_disfavoredOverload
func beginSheetModal(for sheetWindow: NSWindow) async -> (responseValue: NSApplication.ModalResponse, inputValues: [String]) {
(await beginSheetModal(for: sheetWindow), textFields.map(\.stringValue))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment