React-native: [Text] Auto adjust font size to fit Text node width.

Created on 7 Apr 2015  ·  35Comments  ·  Source: facebook/react-native

Hi! I'm looking for how I can achieve behavior similar to UILabel's adjustsFontSizeToFitWidth=true, but haven't been able to find anything.

Is this possible on a Text node?

Good first issue Locked

Most helpful comment

how complicated is it to have adjustsFontSizeToFit work for Android too?

All 35 comments

+1, this is one of those things that native does much better than web and is really well-suited to shadow-thread computation

:+1: would love to see this, @danscan can you try putting a PR together to add this in?

:+1: me too.

@nicklockwood @sahrens - do you think this is desirable to include in core? any thoughts for an implementation strategy for this?

I'd be in favour of it. Interesting to consider how it would interact with flexbox though - perhaps it would only work if the width and height are set explicitly?

I'm very new to the JS side of things, but I'd assume that it would shrink rather than wrapping past a specified number of lines.

@MattFoley yes, much like the native behavior on UILabel, the font size would decrease to fit the width.

@nicklockwood - I think it would be ideal if it were to support flex as well - my guess, as someone who is not too deep in this part of the internals, is that we could perform text sizing after the layout pass has computed the container size. cc @ide

Here's a proposal for the API: there is an optional prop called numberOfLines. If this is set, the text shrinks itself until it can fit in that number of lines or fewer (also want a lower bound so we don't end up with illegibly small text), given the available space provided by its parent.

If numberOfLines is not set, then auto-shrinking behavior takes effect only if upper bounds on the width and height of the text component are known. Example scenarios:

  • Both width and height are set
  • Dimension along the main axis is set. Ex: height is set with flexDirection: 'column'. The upper bound of available space along the cross axis is known from the parent.
  • You could specify max-width/max-height instead of width/height in the cases above -- we care only about an upper bound on available space

In these scenarios, the text is allowed to wrap and it shrinks until all of the text can fit in the available space (and again, we have some lower bound so text doesn't become illegible).

And finally, numberOfLines may be combined with a bounded width/height as well.

We already have a numberOfLines property though…

Or are you proposing that we use the existing numberOfLines property, but augment its behavior to include shrinking the text as well as truncating it, with the min size defaulting to current size (no shrinking) unless otherwise specified?

@nicklockwood, exactly -- if the proposed adjustsFontSizeToFitWidth were set to true then the behavior you describe would take effect.

+1 - definitely need this

+1 this would be great

If anyone is interested, I made a really simplistic version of this for now that just tests the width/height of text at various font sizes and chooses the best one: https://gist.github.com/brentvatne/a267d10eabd2d91a8d44

Use with caution ;)

A real implementation of it would be very welcome here

@brentvatne this is awesome!

@danscan - feel free to clean that up / improve it and publish it to npm if you like!

My goal is to get this implemented in the next few days on the ObjC side, and as a prop for Text, adjustsFontSizeToFitWidth.

This is still a big missing piece of React Native. Would love to get #4026 moving along...

Hi there! This issue is being closed because it has been inactive for a while.

But don't worry, it will live on with ProductPains! Check out its new home: https://productpains.com/post/react-native/text-auto-adjust-font-size-to-fit-text-node-width

ProductPains helps the community prioritize the most important issues thanks to its voting feature.
It is easy to use - just login with GitHub. GitHub issues have voting too, nevertheless
Product Pains has been very useful in highlighting the top bugs and feature requests:
https://productpains.com/product/react-native?tab=top

Also, if this issue is a bug, please consider sending a pull request with a fix.
We're a small team and rely on the community for bug fixes of issues that don't affect fb apps.

@mkonicek If you're closing this out, what does that mean for the existing PR at https://github.com/facebook/react-native/pull/4026?

^ +1, this would be great to have, not sure how else to cope with varying text length in Android. Lmk if I'm missing something

It's been built on iOS, just needs an Android implementation added.

responsiveFontSize from react-native-responsive-dimensions can automatically adjust fontSize based on the device's screen size.

I would like to have also this, so I can define width: 50%, height: 50% and text can fill this on every screen..

Or can one envision a "willWrap" event trigger where changing the font size in the handler have the rendering be recalculated instead of wrapping ?

I managed to overcome this by doing the following.

  1. Pick the font size you like for the current view you have (Make sure it looks good for the current device you are using in the simulator).

  2. import { Dimensions } from 'react-native' and define the width outside of the component like so:
    let width = Dimensions.get('window').width;

  3. Now console.log(width) and write it down. If your good looking font size is 15 and your width is 360 for example, then take 360 and divide by 15 ( = 24). This is going to be the important value that is going to adjust to different sizes.

  4. Use this number in your styles object like so:

    textFontSize: { fontSize = width / 24 },...

Now you have a responsive fontSize.

@wmonecke this is great but I would imagine most were already using this. I think the best way to explain what a lot of the people here want is a % size of the text/views parent. So in my card we are displaying Cards (trading cards) but they are pulled from one component, sometimes there are 3 in a row, someones 2 sometimes 1 taking up whole screen. Could even be 4 or 5.

The point is having a text size that is lets say 50% of the parent (overall card width) is more desirable than device width/height. By using dimensions the text size is the same even when you have 3 items in a row or 2 in a row, which provides inconsistent viewing.

Finally i found this solution that cut the text if is more large than screen size adjustsFontSizeToFit numberOfLines={1} ....

how complicated is it to have adjustsFontSizeToFit work for Android too?

React-native should really solve this out-of-the-box.

I came close to implementing this with the following workaround. Of course this would be exact if you used monospace fonts.

const letterToWidthRatio = 0.5476; // Approximate this by taking the width of some representative text samples
const text = "Some text to display";
const buffer = 5 // arbitrary amount to decrease font size, just in case
const fontSize = containerWidth / (text.length * letterToWidthRatio) - 5;
render() {
  return (
    <View style={{width: containerWidth}}>
      <Text style={{fontSize}}>{text}</Text>
    </View>
  )
}

@JulianKingman How did you approximate letterToWidthRatio? I require something of the sort with the problem I am currently trying to solve.

@Privateomega compare the number of characters with the length, using onLayout

const text = “some example string”
<Text onLayout={({nativEvent: {layout}}) => {condole.log(text.length / layout.width)}}>{text}</Text>

Try a few different strings, and keep in mind punctuation will probably cause problems, so you may want to filter those out in your final font size calculation.

What about this?
https://www.youtube.com/watch?v=JYrpEAz_A1U

I'm not sure that this is new functionality but the video is kinda new, so maybe this is worth to implement in React Native?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

despairblue picture despairblue  ·  3Comments

DreySkee picture DreySkee  ·  3Comments

ghost picture ghost  ·  3Comments

axelg12 picture axelg12  ·  3Comments

anchetaWern picture anchetaWern  ·  3Comments