Skip to main content
The Emoji plugin converts GitHub-style emoji shortcodes (:smile:) into actual emoji characters (😄) both in the editor and in preview mode.

Overview

Type emoji shortcodes and see them rendered as emoji: Input: :smile: :heart: :rocket: Output: 😄 ❤️ 🚀 The plugin works in two contexts:
  1. Editor (Live): Replaces :codes: with emoji while editing
  2. Preview/Reader: Converts :codes: to emoji in rendered markdown
Source: packages/plugins/src/emoji/EmojiPlugin.ts:1-10

Features

GitHub Emoji Support

Supports all GitHub emoji shortcodes:
  • Smileys: :smile: 😄, :laughing: 😆, :blush: 😊
  • Hearts: :heart: ❤️, :blue_heart: 💙, :purple_heart: 💜
  • Hands: :thumbsup: 👍, :clap: 👏, :raised_hands: 🙌
  • Objects: :rocket: 🚀, :book: 📖, :bulb: 💡
  • Nature: :sunny: ☀️, :star: ⭐, :fire: 🔥
  • And 1,800+ more
Source: packages/plugins/src/emoji/emojiMap.ts (complete emoji database)

Selection-Aware Rendering

Emoji rendering is cursor-aware:
// Check if cursor overlaps with emoji range
for (const range of selection.ranges) {
    if (range.from <= end && range.to >= start) {
        overlaps = true;
        break;
    }
}

if (overlaps) {
    // Don't replace - show :code: for editing
    continue;
}

// Replace with emoji widget
const deco = Decoration.replace({
    widget: new EmojiWidget(emoji)
});
When your cursor is on or near an emoji code, it shows :code: so you can edit it. When the cursor moves away, it renders as emoji. Source: packages/plugins/src/emoji/EmojiPlugin.ts:95-107

Viewport Optimization

Only visible emoji are processed:
// Iterate over visible ranges to avoid processing entire document
for (const { from, to } of visibleRanges) {
    const text = view.state.sliceDoc(from, to);
    EMOJI_REGEX.lastIndex = 0;
    
    let match;
    while ((match = EMOJI_REGEX.exec(text)) !== null) {
        // Process emoji in visible range only
    }
}
This ensures smooth performance even in large documents with hundreds of emoji. Source: packages/plugins/src/emoji/emojiExtension.ts:47-50

Implementation

Dual-Context Architecture

The plugin implements emoji conversion in both contexts:
export default class EmojiPlugin extends Plugin {
    async onload(): Promise<void> {
        // 1. Post Processor for Preview Mode / Reader View
        this.registerMarkdownPostProcessor((el: IMarkdownElement, _ctx: any) => {
            el.replaceText(EMOJI_REGEX, (match, emojiCode) => {
                const emoji = GITHUB_EMOJI_MAP[emojiCode.toLowerCase()];
                return emoji || match;
            });
        });
        
        // 2. Editor Extension for Live Preview Mode
        const emojiExtension = ViewPlugin.fromClass(/* ... */);
        this.registerEditorExtension(emojiExtension);
    }
}
Source: packages/plugins/src/emoji/EmojiPlugin.ts:37-65

Emoji Widget

Emoji are rendered using CodeMirror widgets:
class EmojiWidget extends WidgetType {
    constructor(private readonly emoji: string) {
        super();
    }
    
    toDOM(_: EditorView): HTMLElement {
        const span = document.createElement('span');
        span.textContent = this.emoji;
        span.className = 'cm-emoji-widget';
        span.style.cursor = 'default';
        return span;
    }
    
    eq(other: EmojiWidget): boolean {
        return other.emoji === this.emoji;
    }
}
Features:
  • Renders emoji as plain text content
  • Non-editable (cursor: default)
  • Lightweight DOM element
  • Equality check for efficient updates
Source: packages/plugins/src/emoji/EmojiPlugin.ts:16-32

Emoji Regex

Emoji codes are matched with a pre-compiled regex:
const EMOJI_REGEX = /:([a-z0-9_+-]+):/gi;
Pattern explanation:
  • : - Opening colon (literal)
  • ([a-z0-9_+-]+) - Capture group: lowercase letters, numbers, underscore, plus, hyphen
  • : - Closing colon (literal)
  • gi - Global, case-insensitive
Examples:
  • Matches: :smile:, :blue_heart:, :+1:
  • Doesn’t match: :SMILE: (uppercase), smile: (no opening), :smile (no closing)
Source: packages/plugins/src/emoji/EmojiPlugin.ts:11

Emoji Map

The emoji database maps shortcodes to Unicode characters:
export const GITHUB_EMOJI_MAP: Record<string, string> = {
    'smile': '😄',
    'laughing': '😆',
    'blush': '😊',
    'heart': '❤️',
    'blue_heart': '💙',
    'rocket': '🚀',
    '+1': '👍',
    '-1': '👎',
    // ... 1,800+ more emoji
};
Source: packages/plugins/src/emoji/emojiMap.ts

Usage Examples

Common Emoji

## Reactions
:+1: :thumbsup: Agree
:-1: :thumbsdown: Disagree
:heart: Love it
:fire: Hot take
:clap: Well done

## Status
:white_check_mark: Complete
:x: Incomplete
:warning: Warning
:information_source: Info

## Objects
:rocket: Launch
:book: Documentation
:bulb: Idea
:wrench: Fix
:sparkles: Feature
Rendered:

Reactions

👍 👍 Agree 👎 👎 Disagree ❤️ Love it 🔥 Hot take 👏 Well done

Status

✅ Complete ❌ Incomplete ⚠️ Warning ℹ️ Info

Objects

🚀 Launch 📖 Documentation 💡 Idea 🔧 Fix ✨ Feature

Commit Messages

:sparkles: Add emoji support
:bug: Fix rendering issue
:memo: Update documentation
:rocket: Deploy version 2.0
:art: Improve code structure
:fire: Remove deprecated code
:recycle: Refactor theme system

Task Lists

- [ ] :pencil: Write documentation
- [x] :hammer: Build feature
- [x] :test_tube: Add tests
- [ ] :rocket: Deploy to production

Notes and Highlights

> :bulb: **Tip**: Use emoji to make your notes more visual

> :warning: **Warning**: This is a breaking change

> :information_source: **Note**: See documentation for details

Emoji Categories

Smileys & People

:smile: :laughing: :blush: :heart_eyes:
:kissing_heart: :stuck_out_tongue_winking_eye:
:sunglasses: :smirk: :neutral_face: :expressionless:

Animals & Nature

:dog: :cat: :mouse: :hamster: :rabbit: :bear:
:panda_face: :koala: :tiger: :lion_face: :cow:
:sunny: :cloud: :umbrella: :snowman: :zap:

Food & Drink

:apple: :orange: :lemon: :cherries: :grapes:
:watermelon: :strawberry: :peach: :pineapple:
:coffee: :tea: :beer: :wine_glass: :pizza:

Activities & Sports

:soccer: :basketball: :football: :baseball:
:tennis: :volleyball: :bowling: :golf:
:bike: :racing_car: :trophy: :medal:

Travel & Places

:rocket: :airplane: :car: :bus: :train:
:ship: :house: :office: :hospital: :bank:
:world_map: :japan: :statue_of_liberty:

Objects

:book: :notebook: :pencil: :crayon: :paintbrush:
:mag: :lock: :key: :hammer: :wrench:
:bulb: :flashlight: :candle: :fire: :bomb:

Symbols

:heart: :blue_heart: :green_heart: :yellow_heart:
:purple_heart: :broken_heart: :star: :sparkles:
:boom: :collision: :dizzy: :sweat_drops:

Finding Emoji Codes

Emoji Cheat Sheet

Use the Emoji Cheat Sheet to find shortcodes.

Common Patterns

Many emoji follow patterns:
  • Skin tones: :wave: + _tone1-5 = :wave_tone1:
  • Flags: :flag_ + country code = :flag_us:
  • Variations: :heart:, :blue_heart:, :purple_heart:

Searching

Most emoji have intuitive names:
  • Think of the object: “rocket” → :rocket:
  • Think of the action: “running” → :running:
  • Think of the symbol: “check mark” → :white_check_mark:

Performance

Regex Performance

The emoji regex is pre-compiled and very fast:
  • Compilation: Once at plugin load
  • Matching: O(n) where n = text length
  • Per emoji: < 0.01ms

Widget Performance

Emoji widgets are lightweight:
  • DOM element: Single <span>
  • Memory: ~100 bytes per emoji
  • Rendering: Instant (native text)

Viewport Optimization

Only visible emoji are processed:
  • Large document (1000 emoji): Only ~50 in viewport
  • Processing time: < 5ms per scroll
  • Memory impact: Minimal

Installation

The Emoji plugin is built-in and enabled by default. To toggle it:
  1. Open Settings → Plugins
  2. Find “Emoji”
  3. Toggle the enable switch

Configuration

The Emoji plugin currently has no user-configurable settings.

Potential Future Settings

  • Emoji style: Native, Twitter, Apple, Google
  • Skin tone preference: Default skin tone for people emoji
  • Custom emoji: Add custom shortcodes
  • Disable in code: Don’t convert emoji in code blocks

Standalone Extension

The emoji extension can be used without the plugin system:
import { emojiExtension } from '@inkdown/plugins/emoji';
import { EditorView } from '@codemirror/view';

const view = new EditorView({
    extensions: [
        // ... other extensions
        emojiExtension()
    ]
});
This is useful for embedding Inkdown’s editor in other applications. Source: packages/plugins/src/emoji/emojiExtension.ts:95-111

Troubleshooting

Emoji not converting

Solutions:
  1. Check the plugin is enabled
  2. Verify you’re using the correct shortcode (lowercase, underscores)
  3. Check that emoji exists in GitHub emoji set
  4. Try restarting Inkdown

Wrong emoji appears

Cause: Shortcode ambiguity or typo. Solution: Use the Emoji Cheat Sheet to verify the correct shortcode.

Emoji reverts to :code:

Cause: Cursor is near the emoji. Behavior: This is intentional - emoji shows as :code: when editing. Solution: Move cursor away to see rendered emoji.

Emoji in code blocks

Issue: Don’t want emoji in code blocks. Current behavior: Emoji converts everywhere, including code blocks. Workaround: Use backticks within code: \:smile\:

Performance issues

Symptom: Slow editor with many emoji. Solutions:
  1. Emoji plugin already uses viewport optimization
  2. Check other plugins aren’t causing slowness
  3. Try disabling emoji plugin temporarily to confirm

API Reference

Plugin Class

export default class EmojiPlugin extends Plugin {
    async onload(): Promise<void>;
    async onunload(): Promise<void>;
}
Source: packages/plugins/src/emoji/EmojiPlugin.ts:37-70

Emoji Extension

function emojiExtension(): Extension
Creates a CodeMirror extension that converts emoji shortcodes. Returns: CodeMirror Extension that applies emoji decorations Source: packages/plugins/src/emoji/emojiExtension.ts:95-111

Emoji Widget

class EmojiWidget extends WidgetType {
    constructor(emoji: string);
    toDOM(view: EditorView): HTMLElement;
    eq(other: EmojiWidget): boolean;
}

Emoji Map

const GITHUB_EMOJI_MAP: Record<string, string>;
Complete mapping of emoji shortcodes to Unicode characters. Source: packages/plugins/src/emoji/emojiMap.ts

Integration with Other Plugins

Live Preview

Emoji plugin works seamlessly with Live Preview:
  • Both use decorations
  • No conflicts
  • Emoji rendered in formatted markdown

Export/Publishing

Emoji convert during export:
  • HTML export: Unicode emoji characters
  • PDF export: Rendered emoji (if font supports)
  • Markdown export: Keeps :shortcodes:

Accessibility

Screen Readers

Emoji are announced by screen readers:
  • Native emoji have built-in descriptions
  • “Smiling face with open mouth” for 😄
  • “Red heart” for ❤️

Keyboard Navigation

Emoji don’t interfere with keyboard navigation:
  • Tab skips over emoji
  • Arrow keys treat emoji as single character
  • Delete removes entire emoji

High Contrast

Emoji visibility in high contrast mode:
  • Native emoji respect OS contrast settings
  • Text-based fallback if emoji fail to render

Unicode Considerations

Encoding

All emoji are UTF-8 encoded:
  • Compatible with all modern systems
  • Safe for file storage
  • Network transmission compatible

Font Support

Emoji rendering depends on system fonts:
  • macOS: Apple Color Emoji
  • Windows: Segoe UI Emoji
  • Linux: Noto Color Emoji (if installed)

Fallback

If emoji font is missing:
  • System may show tofu (□)
  • Or black & white glyph
  • Consider using :shortcode: instead

See Also

Live Preview

Real-time markdown rendering

Emoji Cheat Sheet

Complete emoji reference

CodeMirror Extensions

Creating editor extensions

Plugin Development

Build custom plugins