ImageRenderer fails to render Text views that use @AccessibilityFocusState (.accessibilityFocused)

Environment:

iOS 16.0+

SwiftUI

Problem Description: I am using ImageRenderer to convert a SwiftUI view into a UIImage for sharing purposes. The view renders perfectly fine on-screen. However, in the generated UIImage, specific Text elements completely disappear.

After debugging, I found that the issue is caused by the @AccessibilityFocusState property wrapper. Any Text view that has the .accessibilityFocused(_:) modifier applied to it will be completely missing from the ImageRenderer output. Other views (like Text without the modifier, or Image views) in the exact same hierarchy render perfectly.

It seems that because ImageRenderer renders the view off-screen without a live accessibility environment/tree, the accessibility focus binding silently breaks the layout or rendering of that specific element.

Minimal Reproducible Example:

Here is a generic, drop-in example that demonstrates the bug. When you tap "Capture with ImageRenderer", the resulting image will only contain the subtitle, while the title text vanishes.

import SwiftUI

// 1. The View we want to render
struct ComponentView: View {
    // The accessibility focus state causing the issue
    @AccessibilityFocusState private var isTitleFocused: Bool
    
    var body: some View {
        VStack(spacing: 12) {
            // BUG: This text will NOT appear in the rendered image
            Text("Title (with accessibility focus)")
                .font(.headline)
                .accessibilityFocused($isTitleFocused)
            
            // This text WILL appear normally
            Text("Subtitle (no accessibility focus)")
                .font(.subheadline)
        }
        .padding()
        .background(Color.blue.opacity(0.1))
        .cornerRadius(12)
    }
}

// 2. The Container to test the rendering
struct ContentView: View {
    @State private var renderedImage: UIImage?
    
    var body: some View {
        VStack(spacing: 40) {
            
            // On-screen: Both Title and Subtitle appear perfectly
            VStack {
                Text("Live On-Screen View:")
                    .font(.caption)
                ComponentView()
            }
            
            Button("Capture with ImageRenderer") {
                renderImage()
            }
            .buttonStyle(.borderedProminent)
            
            // Off-screen render: Title is missing!
            if let image = renderedImage {
                VStack {
                    Text("Rendered UIImage Result:")
                        .font(.caption)
                    
                    Image(uiImage: image)
                        .overlay(
                            Rectangle().stroke(Color.red, style: StrokeStyle(lineWidth: 1, dash: [5]))
                        )
                }
            }
        }
        .padding()
    }
    
    @MainActor
    private func renderImage() {
        let renderer = ImageRenderer(content: ComponentView())
        renderer.scale = UIScreen.main.scale
        
        if let uiImage = renderer.uiImage {
            self.renderedImage = uiImage
        }
    }
}

Questions:

  1. Is this a known limitation of ImageRenderer not supporting the accessibility environment?
  2. Is there a way to inject an accessibility environment into ImageRenderer so these modifiers don't break the render?
  3. Are there any cleaner workarounds other than manually stripping accessibility modifiers before rendering?

Thanks for your post and great description. There are many developers here that I’m sure they’ll jump into this thread. But what you see if a SwiftUI behavior. iOS 16, ok I don't think anything changed in the SwiftUI behavior.

ImageRenderer generates its output entirely off-screen. Because the view is never attached to a live UIWindow, it lacks access to the active responder chain, the focus engine, and the accessibility tree. However, this is different as when SwiftUI encounters property wrappers that inherently rely on these live UIKit/AppKit bridges (like @AccessibilityFocusState and sometimes @FocusState), the view update cycle for that specific element silently fails or aborts, resulting in the view being dropped from the layout pass entirely.

While you can inject standard SwiftUI environment values into an ImageRenderer (e.g., renderer.environment(\.colorScheme, .dark)), you cannot inject a mock accessibility tree or a UIWindow context.

The cleanest way to handle this without duplicating your view structures is to use a custom Environment value to flag when a view is being rendered off-screen, combined with a custom ViewModifier to conditionally apply the accessibility focus. Create a simple environment value that tells your views they are currently being rendered into an image.

Now, in no means I'm an expert and this is something I did had to do to render my image off screen. Based on what you have learned you may also want to change your workflow as this is a possibility.

Looking forward to other ideas from developers.

Albert
  Worldwide Developer Relations.

ImageRenderer is not very reliable. I would use UIHostingController + UIGraphicsImageRenderer for iOS, NSHostingView + something else for macOS.

ImageRenderer fails to render Text views that use @AccessibilityFocusState (.accessibilityFocused)
 
 
Q