Software Architect / Entrepreneur

Software Architect / Entrepreneur

Solving React Native Text Wrap

Getting the text to wrap because flexWrap ain't cuttin' it
Share on facebook
Facebook
Share on twitter
Twitter
Share on linkedin
LinkedIn

I don’t know about you, but React Native’s Layout and Flexbox model is confusing  sometimes. That’s because it doesn’t always behave like it does in CSS. Really all you want is React Native text overflow to just wrap and call it a day. But it’s not so straightforward like that.

Lets wrap your head around flexWrap

In React Native, you may be tempted to try the flexWrap because it’s the only option with the word “wrap” in it. There’s even some people recommending using that style, but that style’s main concern is something else: it’s to break flexbox children, not text.

After some research, I found this GitHub issue

Now, the solutions that were successful used the flexWrap option, but upon testing the flexWrap option was redundant. Some of the solutions used “flex: 1” on the parent view. I personally didn’t want to do that since that would negatively affect the layout of my app. I wanted my particular parent view to grow to the available space that was left. 

If you understand “flex: 1” you’ll know that it’ll distribute the dimension in relationship to its siblings. 

Lets say you do the following:

How flex works. It's not related to your muscles.

If you understand “flex: 1” you’ll know that it’ll distribute the dimension in relationship to its siblings. 

Lets say you do the following:

				
					import * as React from "react";
import {View} from "react-native";

<View>
    <View style={{flex: 1}}>
        <Text>One</Text>
    </View>
    <View style={{flex: 2}}>
        <Text>Two</Text>
    </View>
    <View style={{flex: 1}}>
        <Text>Three</Text>
    </View>
</View>

				
			

Notice how there’s three children with “flex: 1”. In this case, the default flexbox direction is column (or vertical), so each children’s height will be distributed equally 1 + 2 + 1 = 4. So the first and last child takes 1/4th of the height, while the middle child gets 2/4ths of the height (or 1/2).

Going back to the text wrap issue in React Native. What I wanted to do was only have the text breaking and not affecting the overall flexbox layout. So in order to do that you’ll need to apply the “flex: 1” to the Text component itself, and for the parent you’ll add “flexDirection: row“.

Here’s how that looks like:

				
					import * as React from 'react';
import { Text, View, SafeAreaView } from 'react-native';

export default function App() {
  return (
    <SafeAreaView style={{flex: 1, flexDirection: 'row', width: 160}}>
        <View style={{width: 50}}>
            <Text>One</Text>
        </View>
        <View style={{flexGrow: 1, flexDirection: 'row'}}>
            <Text style={{flex: 1}}>Two very long text</Text>
        </View>
        <View style={{width: 50}}>
            <Text>Three</Text>
        </View>
    </SafeAreaView>
  );
}

				
			

If you run the previous code you’ll see that it works just fine on native devices, but the text doesn’t wrap for web. So to fix that just add “width: 1” to the Text component like so.

				
					<View style={{flexGrow: 1, flexDirection: 'row'}}>
        <Text style={{flex: 1, width: 1}}>Two very long text</Text>
    </View>
				
			

The secret overflow sauce

It’s this specific combination of parent and child styles that break texts for both native devices and web. If you don’t want to add the “width: 1” across all platforms, you could just use “Platform.OS” and conditionally check for “web”.

So now lets see how that looks with the fix:

				
					import * as React from 'react';
import { Text, View, SafeAreaView } from 'react-native';

export default function App() {
  return (
    <SafeAreaView style={{flex: 1, flexDirection: 'row', width: 160}}>
        <View style={{width: 50}}>
            <Text>One</Text>
        </View>
        <View style={{flexGrow: 1, flexDirection: 'row'}}>
            <Text style={{flex: 1, width: 1}}>Two very long text</Text>
        </View>
        <View style={{width: 50}}>
            <Text>Three</Text>
        </View>
    </SafeAreaView>
  );
}

				
			

I’ve tried that in Brave (essentially Chrome), Safari, Firefox, and Microsoft Edge. They all accept the fix. It doesn’t seem like it’s something officially documented as I’ve tried to look up the W3 docs and there’s nothing that would allude to doing this. So consider this a “hack” just like back in the old days when we had to support IE 6+ (🤢). 

The only thing that I could assume here is that the flex width of the parent is growing to the full size of its child because of “flexGrow: 1” and then adding “width: 1” makes the flex child shrink less than the threshold causing “flexGrow: 1” to use the remainder of the width available from the parent container’s 160 total width. Basically 160 – 50 – 50 (container width minus the 2 views with 50) left us with 60 and that’s what flexGrow used instead of the intrinsic width of the text context which was longer than 60 units (px in web).

I hope this was useful to you and you’re able to create cross-platform React Native apps.

Email Notifications

Never miss a post again! Get my latest articles delivered directly to your inbox and be the first to know about my upcoming course!

Email Notifications

Never miss a post again! Get my latest articles delivered directly to your inbox and be the first to know about my upcoming course!

🙏

Great Choice!

Thanks for enabling notifications! Don’t worry, I hate spam too and I won’t ever disclose your contact information to 3rd parties.