JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 30
  • Score
    100M100P100Q70487F
  • License MIT

Notion-style Tiptap emoji extension for React — supports Twemoji, emoticons, shortcodes, and cross-platform consistency with modern editor UX.

Package Exports

  • @raihancodes/tiptap-extension-twemoji-react

Readme

tiptap-extension-twemoji-react (Notion-style Emoji for Tiptap)

Notion-style emoji extension for Tiptap, built with React.
Powered by Twemoji for consistent cross-platform emoji rendering with a modern editor UX.

If you like this project, ⭐ give it a star, 🎉 become a sponsor or ☕ buy me a coffee

Key Features

  • 🐦️ Twemoji rendering for cross-platform consistency
  • ✨️ Suggested items displayed in a picker grid UI
  • ⬆️⬇️ Arrow key & Tab navigation for fast selection
  • 🎨 Skin tone selector for diverse emoji usage
  • 🆕 Custom emoji support with reactive updates
  • 📋️ Copy & paste functionality — convert between normal emoji and Twemoji (both ways)
  • 🔤 Shortcodes support (e.g., :hug:, ❤️)
  • 😄 Emoticon support (e.g., :), XD, :P)
  • 🌙 Dark Mode support (for Tailwind)
  • 📑 Virtualised emoji list — powered by react-window, handles 2000+ emojis efficiently
  • 🖼️ Grid Layout — 12-column grid with group titles 📂 and tooltips 🏷️
  • 🧩 Components — ready-to-use UI building blocks (e.g., EmojiDrawer, EmojiPopoverTriggerWrapper)

Installation

npm install @raihancodes/tiptap-extension-twemoji-react
# or
pnpm add @raihancodes/tiptap-extension-twemoji-react
# or
yarn add @raihancodes/tiptap-extension-twemoji-react

Example usage

1. Import the extension and add it to your editor:

import { useEditor } from "@tiptap/react";
import { StarterKit } from "@tiptap/starter-kit";
import { TwemojiExtension } from "@raihancodes/tiptap-extension-twemoji-react";

export default function Editor() {
  const editor = useEditor({
    extensions: [StarterKit, TwemojiExtension],
    content: "<p>Hello World!</p>",
    immediatelyRender: false,
  });

  return <EditorContent editor={editor} />;
}

2. Move the Twemoji sprite sheet to public/assets/

Download the image from here then move it to your public/assets/ folder. The image location can be anywhere in your public or on CDN, see here to adjust spriteUrl

3. Congratulations! Twemoji is now working in your editor.

Using Predefined Custom Emojis

// components/Editor.tsx
import * as React from "react";
import { useEditor } from "@tiptap/react";
import { StarterKit } from "@tiptap/starter-kit";
import {
  TwemojiExtension,
  CustomEmoji,
} from "@raihancodes/tiptap-extension-twemoji-react";

export default function Editor() {
  const editor = useEditor({
    extensions: [StarterKit, TwemojiExtension],
    content: "<p>Hello World!</p>",
    immediatelyRender: false,
  });

  const customEmojis: CustomEmoji[] = [
    {
      id: "8177849e-c2c9-424a-a914-ff128ce439c5",
      label: "github-icon",
      url: "...",
    },
    {
      id: "cecf7043-80da-4e3f-b167-6a85de0e464a",
      label: "npm-icon",
      url: "...",
    },
  ];

  React.useEffect(() => {
    if (editor) {
      editor.commands.updateCustomEmojis(customEmojis);
    }
  }, [editor]);

  return <EditorContent editor={editor} />;
}

Using Custom Emojis from Database

Example: Fetching custom emojis from your database

// page.tsx
import { CustomEmoji } from "@raihancodes/tiptap-extension-twemoji-react";

export default async function Page() {
  const { data, error } = await supabase.from("emojis").select("*");

  if (error) {
    console.error("Error fetching emojis:", error);
  }

  const customEmojis = (data ?? []) as CustomEmoji[];

  return <Editor customEmojis={customEmojis} />;
}

Handling Emoji Uploads and Applying Fetched Emojis

"use client";

// components/Editor.tsx

import * as React from "react";
import { useEditor } from "@tiptap/react";
import { StarterKit } from "@tiptap/starter-kit";
import {
  EmojiUploadProps,
  TwemojiExtension,
  CustomEmoji,
} from "@raihancodes/tiptap-extension-twemoji-react";

export default function Editor({
  customEmojis,
}: {
  customEmojis: CustomEmoji[];
}) {
  const handleEmojiUpload: EmojiUploadProps["upload"] = async ({
    emojiName,
    files,
    handleSuccess,
    handleError,
    dismiss,
  }) => {
    // your code
  };

  const handleEmojiOnError: EmojiUploadProps["onError"] = (errorMessage) => {
    // your code
  };

  const handleEmojiOnSuccess: EmojiUploadProps["onSuccess"] = (
    successMessage,
    callback
  ) => {
    // your code
  };

  const editor = useEditor({
    extensions: [
      StarterKit,
      TwemojiExtension.configure({
        customEmojiOptions: {
          upload: handleEmojiUpload,
          onSuccess: handleEmojiOnSuccess,
          onError: handleEmojiOnError,
        },
      }),
    ],
    content: "<p>Hello World!</p>",
    immediatelyRender: false,
  });

  // Applying Fetched Emojis
  React.useEffect(() => {
    if (editor) {
      editor.commands.updateCustomEmojis(customEmojis);
    }
  }, [editor, customEmojis]);

  return <EditorContent editor={editor} />;
}

Choose the approach that best fits your needs

Coming Soon

  • Svelte & Vue support – Use the extension in more frameworks.
  • Emoji Drawer – A mobile-friendly emoji picker, inspired by Notion.
  • Icon Support – Icons for file identifier / metadata, just like in Notion.
  • Performance Optimizations – Making the package smaller and faster.

License

MIT © Raihan Ramadhan