Skip to content

LineHeight is working weird on specific fonts (Android Only) #29232

Closed as not planned

Description

@toy0605

Please provide all the information requested. Issues that do not follow this format are likely to stall.

Description

Multiline texts don't have same line height on specific fonts. (NotoSansCJK= Source Hans Sans, NotoSerifCJK=Source Hans Serif)

It happens on first line.

Screenshot_1593526375
Screenshot_1593241052
Screenshot_1593526370

React Native version:

info Fetching system and libraries information...
System:
    OS: macOS 10.15.5
    CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
    Memory: 7.08 GB / 32.00 GB
    Shell: 5.7.1 - /bin/zsh
  Binaries:
    Node: 14.4.0 - /usr/local/bin/node
    Yarn: 1.22.4 - /usr/local/bin/yarn
    npm: 6.14.4 - /usr/local/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  Managers:
    CocoaPods: 1.9.2 - /usr/local/bin/pod
  SDKs:
    iOS SDK:
      Platforms: iOS 13.5, DriverKit 19.0, macOS 10.15, tvOS 13.4, watchOS 6.2
    Android SDK:
      API Levels: 27, 28, 29
      Build Tools: 28.0.3, 29.0.2, 29.0.3
      System Images: android-29 | Google APIs Intel x86 Atom_64, android-29 | Google Play Intel x86 Atom_64
      Android NDK: Not Found
  IDEs:
    Android Studio: 4.0 AI-193.6911.18.40.6514223
    Xcode: 11.5/11E608c - /usr/bin/xcodebuild
  Languages:
    Java: 1.8.0_252 - /usr/bin/javac
    Python: 2.7.16 - /usr/bin/python
  npmPackages:
    @react-native-community/cli: Not Found
    react: 16.11.0 => 16.11.0
    react-native: 0.62.2 => 0.62.2
  npmGlobalPackages:
    *react-native*: Not Found

Steps To Reproduce

  1. Set lineHeight properly. (not too small, large)
  2. and set fontFamily to custom font which has problem. (NotoSansCJK, NotoSerifCJK)

Expected Results

Every lines have same line height.

like this:
Screenshot_1593241058
Screenshot_1593526424

Snack, code example, screenshot, or link to a repository:

Android Native(No React Native) is fine. This font is NotoSansKR-Regular :
Screenshot_1593241038

iOS is fine:
Simulator Screen Shot - iPhone 8 Plus - 2020-06-27 at 15 57 43

Text Style:

{
    padding: 10,
    fontSize: 12,
    lineHeight: 28,
}

Activity

  1. emin93 commented on Jul 30, 2021

    @emin93

    Unfortunately the issue still persists for me in 0.65.1. But I found a super strange workaround for this issue and would be curious if that also works for you. Maybe it also helps finding out what the underlying issue is.

    Starting Point

    <Text>aaa...</Text>
    
    fontSize: 16,
    lineHeight: 24
    

    Strange workaround

    Add an empty nested Text and give it lineHeight +1 of the parent.

    <Text>aaa...<Text style={{ lineHeight: 24 + 1 }}  /></Text>
    
    fontSize: 16,
    lineHeight: 24
    

    Summary

    I created a component that does the job:

    import { Platform, Text as RNText } from 'react-native';
    
    export const Text = ({ style, children, ...rest }) => (
        <RNText style={style} {...rest}>
            {children}
            {Platform.OS === 'android' && <RNText style={{ lineHeight: style.lineHeight + 0.001 }} />}
        </RNText>
    );
    
    
  2. markdalgleish commented on Sep 24, 2021

    @markdalgleish

    @emin93 Thanks for the workaround!

    I noticed that lineHeight + 1 seems to add a noticeable amount of space to the text node (I'm using react-native-capsize to trim space above capital letters and below the baseline).

    It looks like literally any non-zero difference to the parent line height also fixes it, e.g.lineHeight + 0.001 also works for me and doesn't introduce unwanted space.

  3. emin93 commented on Sep 29, 2021

    @emin93

    @markdalgleish Ah that's good to know, thanks!

  4. markdalgleish commented on Sep 29, 2021

    @markdalgleish

    I also noticed that this bug can affect text nodes on Android when when numberOfLines causes text to truncate, even when it's just a single line of text. Luckily the workaround posted earlier fixes this issue too, but decided to share for completeness.

    Screen Shot 2021-09-30 at 9 13 16 am

  5. stale commented on Jan 9, 2022

    @stale

    Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as a "Discussion" or add it to the "Backlog" and I will leave it open. Thank you for your contributions.

  6. added
    StaleThere has been a lack of activity on this issue and it may be closed soon.
    on Jan 9, 2022
  7. SleeplessByte commented on Jan 10, 2022

    @SleeplessByte

    Not stale.

  8. removed
    StaleThere has been a lack of activity on this issue and it may be closed soon.
    on Jan 10, 2022
  9. manoj-clix commented on Jan 12, 2022

    @manoj-clix

    Unfortunately the issue still persists for me in 0.65.1. But I found a super strange workaround for this issue and would be curious if that also works for you. Maybe it also helps finding out what the underlying issue is.

    Starting Point

    <Text>aaa...</Text>
    
    fontSize: 16,
    lineHeight: 24
    

    Strange workaround

    Add an empty nested Text and give it lineHeight +1 of the parent.

    <Text>aaa...<Text style={{ lineHeight: 24 + 1 }}  /></Text>
    
    fontSize: 16,
    lineHeight: 24
    

    Summary

    I created a component that does the job:

    import { Platform, Text as RNText } from 'react-native';
    
    export const Text = ({ style, children, ...rest }) => (
        <RNText style={style} {...rest}>
            {children}
            {Platform.OS === 'android' && <RNText style={{ lineHeight: style.lineHeight + 0.001 }} />}
        </RNText>
    );
    

    Thanks @emin93 , it's working with your suggested changes.

  10. zecergin commented on Feb 14, 2022

    @zecergin

    The issue still persists for me in 0.64.3. However, the strange workaround from @emin93 works.

  11. emin93 commented on Feb 18, 2022

    @emin93

    Reporting back after a while - this issue is still present. While the provided workaround might solve the issue with the first two lines, it unfortunately is not a "one size fits all" solution. When applied on single line texts it causes the vertical alignment to be off. includeFontPadding and textAlignVertical don't help in that case either.

  12. darrylyoung commented on Jun 14, 2022

    @darrylyoung

    I'm also seeing this issue when trying to correctly align the placeholder text inside the Android-specific SearchBar component from React Native Elements. Unfortunately, the workaround mentioned doesn't work for me, and the placeholder remains too high, so I've had to resort to the crude paddingTop: 3 to give it the nudge it needs. This is with the Poppins font, specifically Poppins_400Regular.

  13. psaikali commented on Aug 26, 2022

    @psaikali

    Can confirm, this is still a bug (using GrotaRounded custom font for instance) on Android.
    But @emin93 weird workaround works indeed!

  14. CapsAdmin commented on Sep 14, 2022

    @CapsAdmin

    I believe this is caused by

    https://github.com/facebook/react-native/blob/main/ReactAndroid/src/main/java/com/facebook/react/views/text/CustomLineHeightSpan.java#L25

    There is some complex logic that tries to center the font in an appropriate way if the line size is below a certain amount. It can happen if the font has unusual metadata, like the capheight being very tall.

    I don't think this happens on IOS or web, at least I don't see it happening in practice nor can I find any code that does it.

    Adding magic offsets to line height will only make it work for that specific font, at that specific size and line height.

  15. felipecsl commented on Mar 31, 2023

    @felipecsl
    Contributor

    I believe this is caused by

    https://github.com/facebook/react-native/blob/main/ReactAndroid/src/main/java/com/facebook/react/views/text/CustomLineHeightSpan.java#L25

    There is some complex logic that tries to center the font in an appropriate way if the line size is below a certain amount. It can happen if the font has unusual metadata, like the capheight being very tall.

    I don't think this happens on IOS or web, at least I don't see it happening in practice nor can I find any code that does it.

    Adding magic offsets to line height will only make it work for that specific font, at that specific size and line height.

    This file has moved to https://github.com/facebook/react-native/blob/main/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/CustomLineHeightSpan.java

    CustomLineHeightSpan claims to exist because of #7546 which seems to have been already fixed, so this workaround might not be needed anymore

  16. KevinvdBurg commented on Jun 13, 2023

    @KevinvdBurg

    This issue still persists. I tried the workaround suggested by @emin93, but it didn't work. To fix it, I added a marginTop specifically for Android. However, it feels somewhat dirty.

        const style = getTextStyle(type);
        const color = getTextColor();
        const lineHeightFix = {marginTop: IS_ANDROID ? 6 : 0}; 
    
        return (
            <Text style={[style, {color}, propStyle, lineHeightFix]} {...otherProps}>
                {children}
            </Text>
        );
    
  17. jerryphm commented on Jun 22, 2023

    @jerryphm

    I'm facing this problem too (version: react-native 0.70.9)

  18. professorkolik commented on Jun 22, 2023

    @professorkolik

    For most of the fonts you should apply ascender/descender metrics to make it render correctly at first and last lines.
    this tool might help you understand https://vertical-metrics.netlify.app/

    Though there are broken fonts (made by font designers) where you should add workarounds 😄

    based on ascender/descender data you can dynamically calculate your padding top

    Though maybe someone has better approach, for me nothing worked except doing all calculations on my own

  19. shixiaoquan commented on Aug 14, 2023

    @shixiaoquan

    Unfortunately the issue still persists for me in 0.65.1. But I found a super strange workaround for this issue and would be curious if that also works for you. Maybe it also helps finding out what the underlying issue is.

    Starting Point

    <Text>aaa...</Text>
    
    fontSize: 16,
    lineHeight: 24
    

    Strange workaround

    Add an empty nested Text and give it lineHeight +1 of the parent.

    <Text>aaa...<Text style={{ lineHeight: 24 + 1 }}  /></Text>
    
    fontSize: 16,
    lineHeight: 24
    

    Summary

    I created a component that does the job:

    import { Platform, Text as RNText } from 'react-native';
    
    export const Text = ({ style, children, ...rest }) => (
        <RNText style={style} {...rest}>
            {children}
            {Platform.OS === 'android' && <RNText style={{ lineHeight: style.lineHeight + 0.001 }} />}
        </RNText>
    );
    

    This solution is awesome, but not work for me.
    It worked when I place {children} after {Platform.OS ........} like below

    import {Platform, StyleSheet, Text as RNText} from 'react-native';
    
    const Text = ({style, children, ...rest}) => (
        <RNText style={style} {...rest}>
            {Platform.OS === 'android' && (
                <RNText
                    style={
                        StyleSheet.flatten(style)?.lineHeight
                            ? {lineHeight: StyleSheet.flatten(style).lineHeight + 0.001}
                            : {}
                    }
                />
            )}
            {children}
        </RNText>
    );
    
  20. sashagreen commented on Aug 30, 2023

    @sashagreen

    For most of the fonts you should apply ascender/descender metrics to make it render correctly at first and last lines. this tool might help you understand https://vertical-metrics.netlify.app/

    Though there are broken fonts (made by font designers) where you should add workarounds 😄

    based on ascender/descender data you can dynamically calculate your padding top

    Though maybe someone has better approach, for me nothing worked except doing all calculations on my own

    Thank you so much! I ran into this issue with custom font after switching to target SDK 33 and this app was immensely useful in showing what to fix in the font to make it behave 'normally'. I ended up rebuilding the font with proper location of glyphs.

  21. carrie503 commented on Sep 15, 2023

    @carrie503

    The solution from @emin93 is nice! But I found that solution can't fix the paragragh problem. The lines still stick together after a newline. If you are facing same issue like me, I have another solution that is based on @emin93's solution.

    export const Text = ({ style, children, ...rest }) => (
        <RNText style={style} {...rest}>
            {children}
            {Platform.OS === 'android' && <RNText style={{ lineHeight: style.lineHeight + 0.001 }} />}
        </RNText>
    );
    const ParagraphText = ({paragraph}): JSX.Element => {
      const textStrings = useMemo(() => paragraph?.split(/\r?\n/), [paragraph]);
    
      const textStringsComponents = useMemo(
        () =>
          textStrings?.map((text, index) => (
            <>
              <Text>
                {text}
              </Text>
              {!!textStrings && index !== textStrings.length - 1 && (
                <Text>
                  {'\n'}
                </Text>
              )}
            </>
          )),
        [color, content, textStrings, variant, weight]
      );
    
        const transformedChildren = useMemo(
        () => (Platform.OS === 'android' ? textStringsComponents : paragraph),
        [paragraph, textStringsComponents]
      );
      return (
        <Text>
          {transformedChildren}
        </Text>
      );
  22. fabOnReact commented on Jan 16, 2024

    @fabOnReact
    Contributor

    Do you still experience this issue? If yes, I will publish the fix in the react-native-improved package https://github.com/fabriziobertoglio1987/react-native-improved. Thanks a lot

  23. XantreDev commented on Jan 25, 2024

    @XantreDev
    Contributor

    This is just crazy that this issue still a problem. @fabOnReact Can it be fixed without patches?)

  24. XantreDev commented on Jan 25, 2024

    @XantreDev
    Contributor

    My workaround. Is not breaking ref, works as drop in replacement

    pnpm i react-fast-hoc
    import React from 'react';
    import { transformProps } from 'react-fast-hoc';
    import * as RN from 'react-native';
    
    // Fix of android lineHeight problems https://github.com/facebook/react-native/issues/29232#issuecomment-1721080348
    if (RN.Platform.OS === 'android') {
      // Clone text since we modify it
      const OriginalText = Object.assign({}, RN.Text);
      Object.assign(
        RN.Text,
        transformProps(RN.Text, (props) => {
          const style = RN.StyleSheet.flatten(props.style);
          if (!style?.lineHeight) {
            return props;
          }
          const children = [
            ...React.Children.toArray(props.children),
            React.createElement(OriginalText, {
              key: '__text_fix',
              style: {
                lineHeight: style.lineHeight + 0.0001,
              },
            }),
          ];
          props.children = children;
          return props;
        }),
      );
    }
    Before

    image

    After

    image

  25. fabOnReact commented on Jan 25, 2024

    @fabOnReact
    Contributor

    @XantreGodlike I believe this should be fixed in rn-core. If the developer needs:

    1. to find this issue (LineHeight is working weird on specific fonts (Android Only) #29232)
    2. read the entire discussion (10-20 comments)
    3. find and apply your patch.

    We have 1000+ issues, the dev would end up not being productive and better develop his app with the Android Sdk or iOS SDK. My patch does not fix 1 issue. I plan to fix 1000-2000 issues.

    I don't think it is even worth documenting this. distributing 1 patch with react-native-improved and fixing the issue at the source is the solution.

  26. fabOnReact commented on Jan 25, 2024

    @fabOnReact
    Contributor

    My workaround. Is not breaking ref, works as drop in replacement

    pnpm i react-fast-hoc
    import React from 'react';
    import { transformProps } from 'react-fast-hoc';
    import * as RN from 'react-native';
    
    // Fix of android lineHeight problems https://github.com/facebook/react-native/issues/29232#issuecomment-1721080348
    if (RN.Platform.OS === 'android') {
     // Clone text since we modify it
     const OriginalText = Object.assign({}, RN.Text);
     Object.assign(
       RN.Text,
       transformProps(RN.Text, (props) => {
         const style = RN.StyleSheet.flatten(props.style);
         if (!style.lineHeight) {
           return props;
         }
         const children = [
           ...React.Children.toArray(props.children),
           React.createElement(OriginalText, {
             key: '__text_fix',
             style: {
               lineHeight: style.lineHeight + 0.0001,
             },
           }),
         ];
         props.children = children;
         return props;
       }),
     );
    }

    Before
    After

    I will text this solution and implement it in rn-core. If you are interested, you can send PR to https://github.com/fabriziobertoglio1987/react-native-improved. Thanks

  27. fabOnReact commented on Jan 25, 2024

    @fabOnReact
    Contributor
  28. XantreDev commented on Jan 25, 2024

    @XantreDev
    Contributor

    @XantreGodlike I believe this should be fixed in rn-core. If the developer needs:

    1. to find this issue (LineHeight is working weird on specific fonts (Android Only) #29232)
    2. read the entire discussion (10-20 comments)
    3. find and apply your patch.

    We have 1000+ issues, the dev would end up not being productive and better develop his app with the Android Sdk or iOS SDK. My patch does not fix 1 issue. I plan to fix 1000-2000 issues.

    I don't think it is even worth documenting this. distributing 1 patch with react-native-improved and fixing the issue at the source is the solution.

    I am sceptical about patching, it can be complicated and unsafe. But maybe you're doing it in the correct way.
    Also our project is 0.72 RN version, so this solution is not appliable for us

  29. XantreDev commented on Jan 25, 2024

    @XantreDev
    Contributor

    https://github.com/facebook/react-native/pull/42655/files

    The issue says that it fixes this bug on new arch

  30. fabOnReact commented on Jan 25, 2024

    @fabOnReact
    Contributor

    The issue does not reproduce when you don't set the lineHeight?

    because every text has by default a lineHeight, which is calculated on their font ascent and descent.

    React Native often does not work well with custom font, because custom font has different font ascent and descent.

    As react native over-rides onMeasure in ReactShadowTextView, it calculates the font lineHeight internally based on their font ascent and descent to calculate the Text height.

    but maybe this does not work with custom fonts.

    The PR from MD Vacca only sets the lineHeight, but when no lineHeight is set, do we really take in account that the Text onMeasure function correctly calculates height based on the custom font Text ascent and descent?

  31. fabOnReact commented on Jan 25, 2024

    @fabOnReact
    Contributor

    Maybe the issue is not fixed on nested text? The current implementation maybe does not support nested text.

    I believe the change now sets 1 lineHeight for the entire Text, so in this case, they would all have lineHeight 20. Previously you could have 2 text with different lineHeight.

    https://github.com/facebook/react-native/pull/42655/files#diff-e14e9099724d0087bcf9e2847733e8a132fbcb18c5f0d77d8867ff30528c704eR275

    for ex.

    <Text style={{lineHeight: 20}}>
    Line height 20
        <Text style={{lineHeight: 30}}>Line Height 30</Text>
     </Text>

    I worked on something similar in the past and I can easily implement it in text.

  32. Hyuchiha commented on Jan 26, 2024

    @Hyuchiha

    In my case, I am using a custom font and only setting the fontSize without specifying a lineHeight. When there are multiple paragraphs or just one, it has a strange effect. In the first lines, it's as if it applies less lineHeight than in the following ones:

    Captura desde 2024-01-26 11-00-24

  33. XantreDev commented on Jan 26, 2024

    @XantreDev
    Contributor

    In my case, I am using a custom font and only setting the fontSize without specifying a lineHeight. When there are multiple paragraphs or just one, it has a strange effect. In the first lines, it's as if it applies less lineHeight than in the following ones:

    Captura desde 2024-01-26 11-00-24

    I think the only solution with this workaround is to use lineHeight explicitly. Because we cannot calc lineHeight from font size

  34. react-native-bot commented on Jul 27, 2024

    @react-native-bot
    Collaborator

    This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

  35. added
    StaleThere has been a lack of activity on this issue and it may be closed soon.
    on Jul 27, 2024
  36. XantreDev commented on Jul 27, 2024

    @XantreDev
    Contributor

    Bump

  37. removed
    StaleThere has been a lack of activity on this issue and it may be closed soon.
    on Jul 28, 2024
  38. jdschin commented on Jan 22, 2025

    @jdschin

    Im also facing this issue

  39. breezertwo commented on Feb 5, 2025

    @breezertwo

    As the solution from @XantreDev did not work for multiline paragraphs for me, I played a bit more with his solution and came up with an approach that does the trick for all sorts of Text in our app.

    This is the workaround we currently use:

    import React from 'react'
    import { transformProps } from 'react-fast-hoc'
    import * as RN from 'react-native'
    
    export const loadAndroidTextWorkarond = () => {
      if (RN.Platform.OS === 'android') {
    
        const OriginalText = Object.assign({}, RN.Text)
        Object.assign(
          RN.Text,
          transformProps(RN.Text, (props) => {
            const { lineHeight } =
              (RN.StyleSheet.flatten(props.style) as RN.TextStyle | undefined) ?? {}
    
            if (!lineHeight) {
              return props
            }
    
            const createFixElement = () =>
              React.createElement(OriginalText, {
                key: `__text_fix_${Date.now() + Math.random()}`,
                style: { lineHeight: lineHeight + 0.001 },
              })
    
            const children = React.Children.toArray(props.children)
              .map((child) => {
                if (typeof child === 'string') {
                  return child
                    .split('\n')
                    .map((text, i) =>
                      i === 0
                        ? [createFixElement(), text]
                        : ['\n', createFixElement(), text],
                    )
                    .flat()
                }
                return [createFixElement(), child]
              })
              .flat()
    
            return {
              ...props,
              children,
            }
          }),
        )
      }
    }

    Call the method somewhere (e.g App.tsx) in a useEffect and the lineHeight should work.

  40. huynextlevel commented on Mar 30, 2025

    @huynextlevel

    Hi, does this issue resolve. I use font NotoSans , with the normal text is working fine. But with special characters don't working. Does anyone have any solution for this?

    • fontSize: 16
    • lineHeight: 24

    String: ✿ ♬ メ ༒ ☉ 亗 〆★ ㏾*㏾*㏾*㏾*㏾*㏾*㏾

    Image

  41. react-native-bot commented on Sep 27, 2025

    @react-native-bot
    Collaborator

    This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

  42. added
    StaleThere has been a lack of activity on this issue and it may be closed soon.
    on Sep 27, 2025
  43. SleeplessByte commented on Sep 27, 2025

    @SleeplessByte

    Stale bots should not exist.

  44. removed
    StaleThere has been a lack of activity on this issue and it may be closed soon.
    on Sep 28, 2025
  45. react-native-bot commented on Mar 27, 2026

    @react-native-bot
    Collaborator

    This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

  46. added
    StaleThere has been a lack of activity on this issue and it may be closed soon.
    and removed
    StaleThere has been a lack of activity on this issue and it may be closed soon.
    on Mar 27, 2026
  47. XantreDev commented on Mar 28, 2026

    @XantreDev
    Contributor

    Bump

  48. react-native-bot commented on Sep 25, 2026

    @react-native-bot
    Collaborator

    This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

  49. added
    StaleThere has been a lack of activity on this issue and it may be closed soon.
    on Sep 25, 2026
  50. react-native-bot commented on Oct 2, 2026

    @react-native-bot
    Collaborator

    This issue was closed because it has been stalled for 7 days with no activity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Platform: AndroidAndroid applications.StaleThere has been a lack of activity on this issue and it may be closed soon.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions