How to reverse a string with emoji in JavaScript
The classic str.split('').reverse().join('') turns every emoji into broken halves. Reverse by grapheme cluster instead with reverse(str) from graphemely.
The fix, copy and paste
import { reverse } from '@kwy404/graphemely';
reverse('hello'); // 'olleh'
reverse('cafe\u{301}'); // 'e\u{301}fac', the accent stays on the e
reverse('a\u{1F1E7}\u{1F1F7}b'); // 'b\u{1F1E7}\u{1F1F7}a', the flag of Brazil survives
Emoji in the code samples are written as JavaScript escapes, for example \u{1F468} for a man. In your own code you can type the emoji directly.
Why the usual one liners break
'a\u{1F600}b'.split('').reverse().join('');
// 'b\uDE00\uD83Da'
// two lone surrogates in the wrong order
[...'a\u{1F1E7}\u{1F1F7}b'].reverse().join('');
// 'b\u{1F1F7}\u{1F1E7}a'
// the regional indicators swap: BR becomes RB
The spread version keeps surrogate pairs together, so it looks right for simple emoji. It still reverses the inside of multi code point sequences: flags turn into different flags or into two letters in boxes, a skin tone modifier moves in front of its emoji, a combining accent jumps to the previous letter, and family emoji fall apart into single people.
Catch it with ESLint
The graphemely ESLint plugin reports these patterns with the no-unsafe-reverse rule:
import graphemely from '@kwy404/graphemely/eslint-plugin';
export default [graphemely.configs.recommended];
Install
npm install @kwy404/graphemely
pnpm add @kwy404/graphemely
yarn add @kwy404/graphemely
bun add @kwy404/graphemely
Works in Node 16 and newer, all modern browsers, Deno and Bun. ESM and CommonJS, TypeScript types included, zero dependencies, about 2 kB gzipped. Try your own text in the playground.
FAQ
split('') splits a string into UTF-16 code units. Reversing them puts the low surrogate before the high surrogate, which leaves two lone surrogates that render as broken boxes.
Only for text without sequences. It keeps code points together but reverses the parts of flags, skin tones, keycaps, ZWJ emoji and combining accents.
Split it into grapheme clusters and reverse those: reverse(str) from graphemely does exactly that.
Related guides
Truncate a string with emoji
Cut text to a length with an ellipsis, never half an emoji.
String length with emoji
Why an emoji has length 2, and how to count what users see.
Split a string into characters
Get the visible characters, not code units or code points.
Substring without breaking emoji
A Unicode safe substring and slice with negative indices.
Remove lone surrogates
Detect and repair the broken halves of emoji.