Editor.js

repository·next·Indexed 12 days ago

https://github.com/codex-team/editor.js

An open source block-style WYSIWYG editor that outputs clean JSON data instead of HTML. It features a flexible plugin system for creating custom content tools, a comprehensive API for block management, caret control, and notifications, and support for Block Tunes to add metadata and custom layouts to blocks. Version 2.31.6.

Tokens
18K
Snippets
64
Records
88
Agent score
98%

What's inside Editor.js

  1. Implement a custom Editor.js Tool class

    next

    A Tool is a class that provides a custom Block type (e.g., Text, Image, Header). To create a tool, you must implement a class structure that includes a constructor and a render method.

    Required Methods

    • constructor({data, config, api, block}): Initializes the tool instance.
      • data: Data to be rendered.
      • config: Special configuration parameters.
      • api: Editor.js API methods.
      • block: Block's API methods.
    • render(): Returns an HTMLElement that will be placed into the Editor.
    • save(): Processes the tool's element in the DOM and returns the block's data.

    Optional Methods

    • validate(data: BlockToolData): boolean | Promise<boolean>: Validates the tool's data before saving. If it returns false, the data won't be saved.
    • merge(data): Specifies how to merge two blocks of the same type (e.g., on Backspace).
    class MyCustomTool {
      constructor({data, config, api}) {
        this.data = data;
        this.api = api;
        this.config = config;
      }
    
      render() {
        const div = document.createElement('DIV');
        div.innerHTML = 'Hello World';
        return div;
      }
    
      save() {
        return { text: 'Hello World' };
      }
    }
  2. How the Toolbar Block Settings work

    next

    The Editor.js Toolbar contains two distinct zones for block settings:

    1. Plugin Settings Zone: A space dedicated to settings specific to a particular plugin. These are defined and implemented by the plugin developer.
    2. Default Settings Zone: A space for universal settings that apply to every block, regardless of the plugin being used. These are implemented using "Tunes".

    When developing a plugin, you can use the renderSettings method to provide plugin-specific HTML. When developing a universal feature, you implement a "Tune".

  3. What are Block Tunes and how to implement them

    next

    Block Tunes allow you to add additional options or metadata to specific Blocks (e.g., marking a block as a "spoiler", adding an anchor, or setting a background).

    To create a Block Tune, you must define a class that implements a static isTune getter returning true. The core requirement is the render() method, which returns an HTMLElement (typically a button) that will be displayed in the Block Settings panel.

    When the Tune's constructor is called, it receives an object containing:

    • api: The Editor's API object.
    • config: The configuration of the Block Tool the Tune is connected to.
    • block: The Block API methods for the connected block.
    • data: The previously saved Tune data.
    class MyTune {
      static get isTune() {
        return true;
      }
    
      render() {
        const button = document.createElement('button');
        button.innerText = 'My Tune';
        return button;
      }
    }
  4. How to create an Inline Toolbar Tool

    next

    Inline Tools are used to manipulate selected fragments of text (e.g., bold, italic, or links). To create one, your class must implement a static getter isInline set to true and provide specific methods to handle rendering and text manipulation.

    Required Methods

    • render(): Returns an HTMLElement representing the button to be added to the Inline Toolbar.
    • surround(range: Range): Receives the selected Range and performs the text wrapping/transformation.
    • checkState(selection: Selection): Returns a Boolean indicating if the tool is currently active for the given selection (used to highlight the button).

    Optional Methods

    • renderActions(): Returns an HTMLElement (like an input or textarea) to be displayed below the main buttons (e.g., for entering a URL in a link tool).
    • clear(): Logic to reset the tool's state (like clearing inputs) when the toolbar opens or closes.
    • static get sanitize(): Provides a configuration object to ensure the HTML tags generated by your tool are not stripped by the editor's sanitizer.
    export default class BoldInlineTool implements InlineTool {
      public static isInline = true;
      public static title = 'Bold';
    
      render() {
        const button = document.createElement('button');
        button.innerHTML = '<b>B</b>';
        return button;
      }
    
      surround(range: Range) {
        // logic to wrap text in <b> tags
      }
    
      checkState(selection: Selection): boolean {
        // logic to check if selection is already bold
        return false;
      }
    }
  5. Understand the Block-Styled model in Editor.js

    next

    Editor.js is a block-styled editor where the content is composed of structural units called Blocks. Each block (e.g., Paragraph, Heading, Image, Video, List) is implemented as a Plugin.

    Users interact with blocks using:

    • Enter: Creates a new block.
    • Plus Button: Opens the Toolbox to select a block type.
    • Inline Toolbar: Used to apply styles or links to selected text fragments.
    • Block Settings (three-dots button): Used to move, delete, or configure specific tool settings (like heading levels).
  6. Configure Tools in EditorJS initialization

    next

    To use your tools, add them to the tools property of the EditorJS configuration object. You can pass the class directly or provide a configuration object to customize settings like inlineToolbar and custom config parameters.

    var editor = new EditorJS({
      holder : 'editorjs',
      tools: {
        text: {
          class: Text,
          inlineToolbar : true,
          // other settings..
        },
        header: Header
      },
      defaultBlock : 'text',
    });
  7. Initialize Editor.js

    next

    To use Editor.js, first provide a container element in your HTML, then initialize the EditorJS class in your JavaScript. You pass a configuration object to the constructor, where the tools key is used to register the plugins you have installed.

    1. Create a container:
    <div id="editorjs"></div>
    1. Initialize the instance:
    import EditorJS from '@editorjs/editorjs'
    
    const editor = new EditorJS({
      tools: {
       // ... your tools
      }
    })
  8. Implement Paste Handling in Tools

    next

    Editor.js allows tools to intercept and process pasted content (HTML, text patterns, or files). To implement this, you must define a static pasteConfig getter and a public onPaste method.

    1. Define pasteConfig patterns

    Your pasteConfig can handle three scenarios:

    • HTML Tags: Provide a tags array. You can also specify which attributes to keep (e.g., { img: { src: true } }).
    • RegExp: Provide a patterns object where keys are names and values are RegExp objects. (Note: Only works if pasted on defaultBlock and string length < 450).
    • Files: Provide a files object with extensions or mimeTypes arrays.

    2. Implement onPaste(event)

    The onPaste method receives a PasteEvent object. You should switch on event.type ('tag', 'pattern', or 'file') to access the event.detail.

    TypeDetail Property
    tagdata (the pasted HTML element)
    patternkey (the matched pattern name) and data (the pasted string)
    filefile (the pasted file object)
    class MyTool {
      static get pasteConfig() {
        return {
          tags: ['H1', 'H2'],
          patterns: {
            youtube: /http(?:s?):\/\/(?:www\.)?youtu(?:be\.com\/watch\?v=|[\w\-\_]*)/
          },
          files: {
            mimeTypes: ['image/png']
          }
        };
      }
    
      onPaste(event) {
        switch (event.type) {
          case 'tag':
            const element = event.detail.data;
            this.handleHTMLPaste(element);
            break;
          case 'pattern':
            const text = event.detail.data;
            const key = event.detail.key;
            this.handlePatternPaste(key, text);
            break;
          case 'file':
            const file = event.detail.file;
            this.handleFilePaste(file);
            break;
        }
      }
    }
  9. Load Block Tools

    next

    Editor.js uses external scripts to represent different block types (e.g., Headers, Lists). You must load these tools separately (via NPM, CDN, or local files) and then register them in the Editor.js configuration object under the tools key.

    <!-- Example: loading the Header tool from CDN -->
    <script src="https://cdn.jsdelivr.net/npm/codex.editor.header@2.1.0/dist/bundle.js"></script>
  10. Implement a custom Tune for the Toolbar

    next

    To add a feature to the Toolbar's default settings zone (available for all blocks), you must implement a "Tune". A Tune must provide two core methods:

    • render(): Returns the HTML string that will be appended to the default settings zone in the toolbar.
    • save(): Extracts and returns the data that needs to be persisted in the block's output.

    The Tune's constructor receives an object containing:

    • api: An object containing public methods from the Editor.js modules (e.g., this.api.blocks.moveDown()).
    • settings: An object containing the block's default state (e.g., cover images, anchors, etc.).
    import IBlockTune from './block-tune';
    
    export default class YourCustomTune implements IBlockTune {
      public constructor({api, settings}) {
        this.api = api;
        this.settings = settings;
      }
    
      render() {
        // Return HTML for the toolbar
        return '<div>...</div>';
      }
    
      save() {
        // Return the data to be saved in the block
        return { customData: 'value' };
      }
    
      someMethod() {
        // Use the API to manipulate blocks
        this.api.blocks.moveDown();
      }
    }