Slate: Backspace does not properly delete complicated emojis

Created on 8 Mar 2019  ·  8Comments  ·  Source: ianstormtaylor/slate

Bug Report: Backspace does not handle complicated emojis

What's the current behavior?

For an emoji that is represented with multiple characters (example: male zombie 🧟‍♂️), attempting to delete this emoji with the backspace key does not work as expected.

The user must hit the backspace key n times where n is the number of characters in the emoji representation.

What's the expected behavior?

Pressing backspace once should delete the emoji.

Reproduction

You can reproduce this on the Slate examples page: https://www.slatejs.org/#/plain-text.
I am using Chrome on Mac 10.14.2

complicated

bug

All 8 comments

I attempted to find my way around this problem with a plugin that detected backspace keys.

const { focusText, selection } = editor.value;
const characterWeBackSpaced = 
  focusText.text.slice(selection.start.offset - 1, selection.offset);

In the case above, the characters are (from left to right) [zombie emoji, "", male emoji, ""]. I guess it would be possible to detect a backspace that results in a "" being deleted, and then determine if the preceding character is an emoji.

But I do not know if this is the consistent construction of complex emojis, or if there is an easier way to accomplish this in the library internals.

Are emojis wrapped into some kind of component or are they plaintext? I think emojis are comprised of a few special characters, that's why complex emojis take longer to delete than the basic ones (more characters stitched together to form an emoji). I'd imagine that to solve that you'll need to wrap every emoji into <span /> and delete them as a block.

@dmitrizzle Right now the emojis are plaintext. The <span /> idea could work!

I think there is a similar issue here - wrapping (any) text in a span programmatically would necessitate a way to ensure we what is an emoji and what is not.

So in the case above: [zombie emoji, "", male emoji, ""]. Which are empty strings, and which are partial representations of a complex emoji

Edit: clarification from @rikkit below (https://github.com/ianstormtaylor/slate/issues/2635#issuecomment-476256288). These are not blank strings but Zero Width Joiners (U+200D)

To me this feels like something that Slate's core should be able to handle. Because any user can use any emoji in any Slate editor and probably no user wants to remove the skin/hair color before removing the face by pressing backspace a single time.

I guess we could implement logic in Slate to know when unicode characters belong to each other being a single emoji?

Btw: moving selection using the arrow keys over a complex emoji does work properly :)

Emoji issue seems to be much bigger than that for me (not sure if Linux specific).

@grsmvg Every pasted emoji takes several arrow key presses in Slate to move the selection over "for real", first press moves caret visually over but when I type a character or press Enter, emoji gets split into two � characters. No such issue in native contenteditable.

  • Regular emojis take 2 arrow key presses
  • Complex emojis (e.g with skin tone) take 4 arrow key presses

@adjourn I just reproduced this on Mac, so it is not Linux-specific.

@scottluptowski you wrote above

So in the case above: [zombie emoji, "", male emoji, ""]. Which are empty strings, and which are partial representations of a complex emoji

From Emojipedia:

The Man Zombie emoji is a sequence of the 🧟 Zombie and ♂ Male Sign emojis. These are combined using a zero width joiner between each character and display as a single emoji on supported platforms.

... those empty strings are actually zero-width joiners. Here's a list of all emoji with ZWJs.

I'm not sure of all the implications on this suggestion since I've only just started looking at the Slate codebase, but it feels like a quick win could be to make backspacing "skip over" the ZWJ character (U+200D) - when it's pressed, it deletes the ZWJ plus the preceding emoji. The ZWJ character needs to remain in the text, so that the OS can display the emoji properly, so the change would just reduce the number of times backspace needs to be pressed - "male zombie" would take 2 rather than 4 backspaces (the first backspace would delete ♂, leaving 🧟)

I think it's up for debate whether it's expected to be able to delete ZWJ emojis in one or multiple keypresses. Just as a reference though, the GitHub comment editor requires two backspaces to delete male zombie, not one.

for reference:

  • male zombie: 🧟‍♂️
  • zombie: 🧟

Your input (and maybe wacky use cases which might break it) is greatly appreciated in #2680 .

CC: @grsmvg @scottluptowski @rikkit

Was this page helpful?
0 / 5 - 0 ratings