Imaging we need to build a simple UI for an article preview. Something like this one:
Let's start building it from the bottom. Why not? 🙃
We can use the Pressable and Text components to create the "Learn more" button.
import { Text, Pressable } from 'react-native'
type Props = {
children: string
}
export const Button = ({ children }: Props) => {
return (
<Pressable style={({pressed}) => ({
padding: 12,
borderWidth: 1,
borderRadius: 6,
backgroundColor: pressed ? 'lightyellow' : 'white',
})}>
<Text>{children}</Text>
</Pressable>
)
}
Pretty simple, right?
But wait, why the button is stretched full width? 🤔
We did not use the flex: 1
, flexGrow: 1
, or width: '100%'
in our styles. 😬
Let's try to find the answer in the React Native Flexbox docs.
flex
will define how your items are going to “fill” over the available space along your main axis.
Ok, flex
controls only the "main" axis. But what is the "main" axis?
flexDirection
controls the direction in which the children of a node are laid out. This is also referred to as the main axis. The cross axis is the axis perpendicular to the main axis, or the axis which the wrapping lines are laid out in (flexDirection
is default tocolumn
).
So, according to the docs the "main" axis for React Native by default is directed from top to bottom (which is different for the web❗️). It means, that in our case, flex
and flexGrow
styles do not affect the width of the button.
And what about the "cross" axis?
alignItems
describes how to align children along the cross axis of their container. It is very similar tojustifyContent
but instead of applying to the main axis,alignItems
applies to the cross axis (alignItems
is default tostretch
).
Eureka! That is it. As we can see now, for every element we add, the default behaviour for the "cross" axis will be stretch
. That is why our button is stretched full width.
Let's try to fix it!
To do that, we need to change the "align" style for the "cross" axis, right? Theoretically, we can wrap the Pressible
component with the View
component and set the alignItems
style for the wrapper View
component to flex-start
.
import { Text, Pressable, View } from 'react-native';
type Props = {
children: string;
};
export const Button = ({ children }: Props) => {
return (
<View style={{ alignItems: 'flex-start' }}>
<Pressable
style={({ pressed }) => ({
padding: 12,
borderWidth: 1,
borderRadius: 6,
backgroundColor: pressed ? 'lightyellow' : 'white',
})}>
<Text>{children}</Text>
</Pressable>
</View>
);
}
Looks good! 😻
But can we do it better without the "extra" View
component? The answer is yes, we can! 💪
alignSelf has the same options and effect as alignItems but instead of affecting the children within a container, you can apply this property to a single child to change its alignment within its parent.
Wow, that is exactly what we need! 🎉
We just need to apply the alignSelf: 'flex-start'
style to the Pressible
component. Let's try it.
import { Text, Pressable } from 'react-native';
type Props = {
children: string;
};
export const Button = ({ children }: Props) => {
return (
<Pressable
style={({ pressed }) => ({
padding: 12,
borderWidth: 1,
borderRadius: 6,
backgroundColor: pressed ? 'lightyellow' : 'white',
alignSelf: 'flex-start',
})}>
<Text>{children}</Text>
</Pressable>
);
};
Yey! It is what we wanted to achieve. 🥳
Awesome! I feel like we learned a lot just by building a simple button. That's amazing! 😊
Please, press the 💖 button, if you like this article, and have a happy hacking! 🙌🏻
P.S. You can play with the code using this Expo Snack.
Credits
Photo by kike vega on Unsplash
Image by Susann Mielke from Pixabay
Top comments (0)