react-native-paper
react-native-paper copied to clipboard
fix: fixed `Chip` "shadow" and height issue
Motivation
There is an issue with the Chip component when a Chip with mode="outlined" is used next to one with mode="flat" (see screenshot). The Chip with mode="flat" displays a kind of "shadow" at the bottom.
This problem is caused by the Surface component, which splits styles provided via props into outerLayerViewStyles and innerLayerViewStyles. Specifically, it is caused by the backgroundColor, which has the same value in both outerLayerViewStyles and innerLayerViewStyles (see below, reference):
const outerLayerViewStyles = {
...(isElevated && getStyleForShadowLayer(elevation, 0)),
...outerLayerStyles,
...borderRadiusStyles,
backgroundColor: bgColor,
};
const innerLayerViewStyles = {
...(isElevated && getStyleForShadowLayer(elevation, 1)),
...filteredStyles,
...borderRadiusStyles,
flex: flattenedStyles.height ? 1 : undefined,
backgroundColor: bgColor,
};
A Chip with mode="outlined" is 2dp larger in width and height than one with mode="flat" due to its borderWidth of 1dp. When both modes are placed next to each other, the outer View of the Surface component adjusts to fill the height difference, but the inner View does not. Since the background color for a disabled Chip uses RGBA (with opacity), the inner and outer background colors create overlapping layers, resulting in the visible "shadow" at the bottom.
Possible solutions
1. Adding flexGrow: 1 to the Surface used inside Chip component
Adding flexGrow: 1 would resolve the issue by allowing the inner View of the Surface to grow and match the height of the outer View. However, because outerLayerStylesProperties includes flexGrow, it won't be applied to the inner layer out of the box. To manage this, we could pass separate props like innerLayerStyles and outerLayerStyles. However, this approach might affect other components using Surface, making it a more complex solution.
2. Setting borderWidth:1 for both modes and within the flat mode setting the borderColor to transparent (implemented here)
IMO this is the least impactful solution. It ensures both modes have matching dimensions (width and height) and restricts the change to the Chip component itself.
Related issue
https://github.com/callstack/react-native-paper/issues/4457
Test plan
You can test it by changing ChipExample.tsx
<View style={styles.container}>
<Chip mode="outlined" selected={false}>
Not selected, enabled
</Chip>
<Chip mode="flat" selected disabled>
Selected, disabled
</Chip>
</View>
const styles = StyleSheet.create({
container: {
marginTop: 16,
flexDirection: 'row',
justifyContent: 'space-around',
},
});
Hey @kamilkedzierski, thank you for your pull request 🤗. The documentation from this branch can be viewed here.