Fix React Native Text Cutoff on OnePlus & Oppo Devices

Author

Spencer Carli

Developer, cat dad, and devout pizza lover. Teaching at React Native School and building apps with Handlebar Labs.

Last Updated: February 3, 2021

React Native has an issue with rendering the default OnePlus Slate font. This has been an issue for a while in React Native.

I ran into this issue a few weeks ago and we recently had a question come up in the React Native School community about this. So what to do about it?

Note: A few people have had success with adding textBreakStrategy='simple' to the Text component. For whatever reason that didn't work for me but I would suggest doing that before jumping through the hoops mentioned below.

There are a few options:

  1. Add a ' ' to the end of every string (yuck).
  2. Set a fixed width on the text (yuck).
  3. Specifically set the font family on trouble devices (yuck).

None of these are great solutions but we'll be using the third option - I've found it to work best and I've been running the code in production for a while with no issues.

This pull request is the original source of the code. I'm reposting it so you don't have to dig through Github issues to find it - I hope the search algorithm brought you here early in your quest.

The Solution

// AndroidFontFix.js

import React from 'react';
import { Platform, StyleSheet, Text } from 'react-native';
import { getManufacturerSync } from 'react-native-device-info';

export function enableAndroidFontFix() {
  if (Platform.OS !== 'android') {
    return;
  }

  let manufacturer = getManufacturerSync();

  let styles;

  switch (manufacturer) {
    case 'OnePlus':
      styles = StyleSheet.create({
        androidFontFixFontFamily: {
          fontFamily: 'Slate',
          // fontFamily: 'Roboto',
        },
      });
      break;

    case 'Oppo':
      styles = StyleSheet.create({
        androidFontFixFontFamily: {
          // fontFamily: 'Oppo Sans', // not sure of the name of the font
          fontFamily: 'Roboto',
        },
      });
      break;

    case 'LG': // https://github.com/facebook/react-native/issues/15114#issuecomment-366066157
      styles = StyleSheet.create({
        androidFontFixFontFamily: {
          // We don't know the default fontFamily for the LG platform
          fontFamily: 'Roboto',
        },
      });
      break;

    default:
      return;
  }

  let __render = Text.render;
  Text.render = function (...args) {
    let origin = __render.call(this, ...args);
    return React.cloneElement(origin, {
      style: [styles.androidFontFixFontFamily, origin.props.style],
    });
  };
}
// index.js
import { enableAndroidFontFix } from './AndroidFontFix';

enableAndroidFontFix();

// ... Render app

Explanation

So, what's going on with the code above?

First, we don't run anything if the Platform isn't android because, as far as I've seen, this is not an iOS problem.

We then get the manufacturer of the device. This allows us to do custom work for the devices in question while leaving platforms that work alone.

Then, for target manufacturers we explicitly set the fontFamily to be used. This will override whatever the system font is and tell React Native how to measure things so nothing gets cutoff.

Finally, we override the Text component's render method by cloning it and applying our text override styles ensuring that the fontFamily for every single Text will have at least a fontFamily on it.

Since we're overriding the Text component's render we need to make sure we run our enableAndroidFontFix immediately before our app runs.

Conclusion

I don't like this solution. It's brittle and relies on guesswork to get things to work.

But it's the best solution I've found for now.

Have a better one? Let me know.

React Native School Logo

React Native School

Want to further level up as a React Native developer? Join React Native School! You'll get access to all of our classes and our private Slack community.

Join the email list to be notified of all new lessons and classes!