Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Emojis inside <Text> increase line-height or stretch the element #18559

Closed
3 tasks done
rikur opened this issue Mar 26, 2018 · 7 comments
Closed
3 tasks done

Emojis inside <Text> increase line-height or stretch the element #18559

rikur opened this issue Mar 26, 2018 · 7 comments
Labels
Stale There has been a lack of activity on this issue and it may be closed soon.

Comments

@rikur
Copy link

rikur commented Mar 26, 2018

Environment

Environment:
OS: macOS High Sierra 10.13.3
Node: 9.4.0
Yarn: 1.3.2
npm: 5.6.0
Watchman: 4.9.0
Xcode: Xcode 9.2 Build version 9C40b
Android Studio: 3.0 AI-171.4443003

Packages: (wanted => installed)
react: ^16.3.0-alpha.1 => 16.3.0-alpha.3
react-native: 0.54.2 => 0.54.2

Steps to Reproduce

Render a <Text> component with an emoji inside it.

Expected Behavior

Have text with emojis inside a text not change the line-height. Also expecting textDecorationLine: 'line-through' to work seamlessly with emojis inside text.

Actual Behavior

The line-height of the entire text is increased. It's even more prevalent if you apply textDecorationLine: 'line-through' on the text, as shown below.

screen shot 2018-03-26 at 3 11 18 am

screen shot 2018-03-26 at 3 11 31 am

@react-native-bot react-native-bot added the Platform: macOS Building on macOS. label Mar 26, 2018
@rikur
Copy link
Author

rikur commented Mar 27, 2018

Here's my far from perfect workaround that obviously is tied to the styles of my font in question:

const emojiRe = /(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|[\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|[\ud83c[\ude32-\ude3a]|[\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])/g

const EmojiText = (props) => {
  const content = props.children
  const fontSize = 11
  const emojis = content.match(emojiRe)
  const strings = content.split(emojiRe)
  return <Text {...props}>{strings.map((v, i) => <Text>{v}<Text style={{ fontSize }}>{emojis[i]}</Text></Text>)}</Text>
}

I noticed that similar issues with emojis happen outside of React Native. Pages renders the emojis correctly, Sketch doesn't. It seems like Sketch automatically assign a special font for emojis that I can't even change.

@hramos hramos removed the Platform: macOS Building on macOS. label Mar 29, 2018
@ccfz
Copy link

ccfz commented May 31, 2018

I have been looking into this issue for a while now and there are some hacky solutions out there related to adjusting the fontSize / lineHight etc. The issue does not arise when one uses System in FontFamily, which to my understanding is related to the way System font was implemented in react-native with IOS/Android presets #1635. The problem with Systemis that it does not allow for font variations such as SF UI Display. @rikur solution worked for me but I was looking for a way to avoid the font style dependency What I discovered is that if I apply the System fontFamily to just the emoji it will behave as expected without having to add custom fontSize.

So based on the code from @rikur I just changed the fontSize: 11 to fontFamily: System.

In our project we are only using variants of San Fransico font and since System is SF UI Text it might only work with variants of the default system fonts. I am interested to see if this works with other custom fonts as well.

For convenience the snippet from @rikur the way I implemented it and with the fontFamilychange.

import React from 'react';
import { Text } from 'react-native';

const EmojiText = ({ style, children, ...rest }) => {
  // eslint-disable-next-line
  const emojiRe = /(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|[\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|[\ud83c[\ude32-\ude3a]|[\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])/g
  const emojis = children.match(emojiRe);
  const strings = children.split(emojiRe);

  function renderEmoji(index) {
    if (emojis === null) { return null; }

    return (
      <Text style={{ fontFamily: 'System' }}>
        {emojis[index]}
      </Text>
    );
  }

  return (
    <Text style={style} {...rest}>
      {strings.map((value, index) => (
        <Text>
          {value}
          {renderEmoji(index)}
        </Text>
      ))}
    </Text>
  );
};

export default EmojiText;

@rikur
Copy link
Author

rikur commented May 31, 2018

Thanks for the update. I just tried your snipped at it doesn't seem to work when used with custom fonts.

@jakehasler
Copy link

@rikur I was able to get this working decently with a custom font. I updated the last return block to the following:

return (
    <Text {...rest}>
      {strings.map((value, index) => (
        <Text style={style} key={index}>
          {value}
          {renderEmoji(index)}
        </Text>
      ))}
    </Text>
  );

@scottmas
Copy link

The best solution I've found is the use react-native-parsed-text like so:

const EMOJI_REGEX = /(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|[\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|[\ud83c[\ude32-\ude3a]|[\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])/g;
function EmojiText({children, ...rest}) {
  return (
    <ParsedText {...rest} parse={[{ pattern: EMOJI_REGEX, style: { fontFamily: "System" } }]}>
      {children}
    </ParsedText>
  );
}

@stale
Copy link

stale bot commented Oct 24, 2018

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 "For Discussion" or "Good first issue" and I will leave it open. Thank you for your contributions.

@stale stale bot added the Stale There has been a lack of activity on this issue and it may be closed soon. label Oct 24, 2018
@stale
Copy link

stale bot commented Oct 31, 2018

Closing this issue after a prolonged period of inactivity. If this issue is still present in the latest release, please feel free to create a new issue with up-to-date information.

@stale stale bot closed this as completed Oct 31, 2018
@facebook facebook locked as resolved and limited conversation to collaborators Nov 1, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Stale There has been a lack of activity on this issue and it may be closed soon.
Projects
None yet
Development

No branches or pull requests

6 participants