SwiftUI Text components no longer adjust their contrast in the presence of vibrancy on Ventura

Text views that rest within SwiftUI popover (or NSPopover) components no longer adjust their vibrancy and color values correctly. This results in text being "washed out" if rendered over a background that clashes with the text color. This feels like a significant regression with wide-reaching impact.

Reproducing this is trivial, can be done in pure SwiftUI or a combination of SwiftUI and AppKit, and the differences between Monterey and Ventura can be seen clearly. See here for a sample project: https://github.com/pwerry/BrokenTextVibrancyOnVentura

The workaround is to fall back to using NSTextView and NSTextField components wrapped in an NSViewRepresentable.

Filed a feedback report: FB11742402

Answered by robfeldmann in 751904022

I noticed this bug today and came up with the following extension as a workaround for folks that don't want to fall back to using NSTextView or NSTextField as OP did.

extension Color {
	/// Creates an adaptive color from the given dynamic `NSColor` instance.
	///
	/// The color will correctly respond to changes to the current `NSAppearance`.
	///
	/// Example:
	/// ```swift
	/// Text("Hello, World!")
	///   .foregroundColor(.adaptive(.labelColor))
	/// ```
  ///	
  /// This is one possible workaround for a SwiftUI bug that prevents colors from being correctly rendered,
	/// such as when presented inside a `popover` or `NSPopover`.
	///
	/// - See Also: [SwiftUI text components no longer adjust their contrast in the presence of vibrancy on Ventura](https://developer.apple.com/forums/thread/721069)
	/// - Parameter color: A dynamic `NSColor` instance (e.g. `.labelColor`).
	/// - Returns: A color that correctly renders for the current `NSAppearance`.
	public static func adaptive(_ color: NSColor) -> Self {
		.init(nsColor: NSColor(name: nil) { _ in
			return color
		})
	}
}

This uses NSColor's init(name:dynamicProvider:) method under the hood, which is called when/if the app's appearance changes.

Here is an example of the above helper in use:

ContentView()
  .popover(isPresented: $isPresented) {
    Text("Fixed Text Vibrancy")
      .foregroundColor(.adaptive(.labelColor))
      .padding()
  }
Accepted Answer

I noticed this bug today and came up with the following extension as a workaround for folks that don't want to fall back to using NSTextView or NSTextField as OP did.

extension Color {
	/// Creates an adaptive color from the given dynamic `NSColor` instance.
	///
	/// The color will correctly respond to changes to the current `NSAppearance`.
	///
	/// Example:
	/// ```swift
	/// Text("Hello, World!")
	///   .foregroundColor(.adaptive(.labelColor))
	/// ```
  ///	
  /// This is one possible workaround for a SwiftUI bug that prevents colors from being correctly rendered,
	/// such as when presented inside a `popover` or `NSPopover`.
	///
	/// - See Also: [SwiftUI text components no longer adjust their contrast in the presence of vibrancy on Ventura](https://developer.apple.com/forums/thread/721069)
	/// - Parameter color: A dynamic `NSColor` instance (e.g. `.labelColor`).
	/// - Returns: A color that correctly renders for the current `NSAppearance`.
	public static func adaptive(_ color: NSColor) -> Self {
		.init(nsColor: NSColor(name: nil) { _ in
			return color
		})
	}
}

This uses NSColor's init(name:dynamicProvider:) method under the hood, which is called when/if the app's appearance changes.

Here is an example of the above helper in use:

ContentView()
  .popover(isPresented: $isPresented) {
    Text("Fixed Text Vibrancy")
      .foregroundColor(.adaptive(.labelColor))
      .padding()
  }
SwiftUI Text components no longer adjust their contrast in the presence of vibrancy on Ventura
 
 
Q