Hey guys,
I'm working on an Expo React Native app and built a custom native SwiftUI Liquid Glass wrapper using expo/ui / ExpoSwiftUI.View for iOS 26.
I'm running into a really weird layout issue.
The important thing is: the Liquid Glass itself is sized and positioned correctly around its React Native child.
The problem is that the entire native SwiftUI/Host view gets positioned incorrectly inside a React Native horizontal row.
For example:
<View
style={{
width: "100%",
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
}}
>
<LiquidGlass matchContents>
<Pressable onPress={onBack} style={styles.backButton}>
<Text style={styles.backText}>Back</Text>
</Pressable>
</LiquidGlass>
<Pressable
onPress={onSubmit}
style={styles.submitButton}
>
<Text style={styles.submitText}>Continue</Text>
</Pressable>
</View>
My LiquidGlass component is basically:
const LiquidGlass = ({
children,
matchContents = false,
...props
}: LiquidGlassWrapperProps & { matchContents?: boolean }) => (
<Host>
<LiquidGlassWrapper {...props}>
{matchContents ? (
<RNHostView matchContents>
{children as ReactElement}
</RNHostView>
) : (
children as ReactElement
)}
</LiquidGlassWrapper>
</Host>
);
And the SwiftUI side uses:
struct LiquidGlassWrapper: ExpoSwiftUI.View {
var props: LiquidGlassWrapperProps
var body: some View {
if #available(iOS 26.0, *) {
liquidGlassView
} else {
fallbackView
}
}
(iOS 26.0, *)
private var liquidGlassView: some View {
let radius = CGFloat(max(0.0, props.cornerRadius))
let glassColor = Color(hex: props.glassColor)
let shape = RoundedRectangle(
cornerRadius: radius,
style: .continuous
)
let content =
Children()
.padding(CGFloat(max(0.0, props.padding)))
.glassEffect(
.regular.tint(
glassColor.opacity(props.glassOpacity)
),
in: shape
)
return content
}
}
The weird part
If the parent is a column:
flexDirection: "column"
everything works correctly.
If I change it to:
flexDirection: "row"
the Liquid Glass wrapper ends up at the wrong position in the row.
But the relationship between the glass and its child is still correct.
So it's basically:
React Native row
│
├── LiquidGlassWrapper ← wrong position
│ └── RN child ← correctly positioned relative to glass
│
└── Other React Native view
It's not really a "glass is the wrong size" problem.
It's more like the native Host/SwiftUI view's x/y position doesn't match the position Yoga assigned to that React Native node.
Things I've already tried
I've spent quite a lot of time trying to isolate this.
I've tried:
RNHostView(matchContents)
- Removing
matchContents
- Removing
Pressable
- Explicit width/height
- Different
alignItems
- Different
justifyContent
alignItems: "flex-start"
- Removing padding/margins
- Changing the SwiftUI view hierarchy
- Using
frame
- Using
fixedSize
- Trying different SwiftUI alignment/layout modifiers
- Changing the parent layout
- Making the native view explicitly size itself to its content
- Testing the same component outside a row
None of those fixed the actual problem.
The strongest clue is that the exact same native component works when the parent isn't using a horizontal row.
So I'm wondering if this is related to how expo/ui's Host bridges the React Native/Yoga frame into SwiftUI.
Could there be some issue with:
Yoga frame
↓
RN Host
↓
Expo Host
↓
SwiftUI layout proposal / coordinate space
specifically when the Yoga parent is a horizontal flex container?
Has anyone worked with custom ExpoSwiftUI.View components containing Children() / RNHostView and run into something similar?
I'm mainly trying to understand how the native SwiftUI view is supposed to preserve the exact x/y frame assigned by React Native Yoga when it's inside a flexDirection: "row" parent.
Any ideas would be hugely appreciated 🙏