I’m embedding a SwiftUI `View` inside a `UIViewCon...
# compose-ios
g
I’m embedding a SwiftUI
View
inside a
UIViewController
using
UIHostingController
, and then presenting that controller inside a Jetpack Compose
UIKitViewController
. Even though I set
opaque = false
, the SwiftUI content always appears with an opaque background. Why? 🧵
My SwiftUI view is a simple button with a custom `ButtonStyle`:
Copy code
var body: some View {
    Button(action: { shuffle() }) {
        Text("Shuffle")
            .font(.body)
            .foregroundColor(.white)
            .padding(.horizontal, 20)
            .padding(.vertical, 10)
    }
    .buttonStyle(PillButtonStyle())
}

struct PillButtonStyle: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .background(
                Capsule()
                    .fill(Color.blue)
            )
            .scaleEffect(configuration.isPressed ? 0.96 : 1)
            .opacity(configuration.isPressed ? 0.85 : 1)
    }
}
The SwiftUI view is wrapped like this:
Copy code
private class ButtonViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()

        let swiftUIView = ButtonView()
        let hostingController = UIHostingController(rootView: swiftUIView)

        addChild(hostingController)
        view.addSubview(hostingController.view)

        hostingController.view.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            hostingController.view.topAnchor.constraint(equalTo: view.topAnchor),
            hostingController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            hostingController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            hostingController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor)
        ])

        hostingController.didMove(toParent: self)
    }
}
Note: currently I’m only using
UIHostingController(rootView: swiftUIView)
since the remaining configurations seem to be ignored:
Copy code
struct ComposeView: UIViewControllerRepresentable {
    let controller: UIViewController
    func makeUIViewController(context: Context) -> UIViewController {
        MainViewControllerKt.MainViewController(controller: controller)
    }

    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
    }
}

struct ContentView: View {
    var body: some View {
        ComposeView(controller: UIHostingController(rootView: ButtonView(onClick: { })))
}
On the Compose side, I’m using:
Copy code
ComposeUIViewController(configure = { opaque = false }) {
    Box(contentAlignment = Alignment.Center) {
    Crossfade(targetState = state) {
        ...
    }
    UIKitViewController(
        factory = { controller },
    )
}
On the other hand, this works in Swift:
Copy code
struct View: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> UIViewController {
        let controller = UIHostingController(rootView: ButtonView(onClick: {}))
        controller.view.backgroundColor = .clear
        return controller
    }

    func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
    }
}

struct ContentView: View {
    var body: some View {
        ZStack {
            Color.black.ignoresSafeArea()
            View()
                .frame(width: 98, height: 40)
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
    }
}
Which makes me believe the problem is on the Compose side.
Simulator Screenshot - iPhone 17 Pro - 2025-12-29 at 11.12.15.png
I’ve been digging around and found out a solution: we must set
controller.view.backgroundColor = UIColor.clearColor
inside
Copy code
UIKitViewController(
    factory
from Compose, otherwise it will ignore the configurations from Swift. I believe this could be a bug, I’ve opened an issue about this too: https://youtrack.jetbrains.com/issue/CMP-9469/SwiftUI-background-transparency-configured[…]stingController-is-ignored-by-Compose-UIKitViewController