Next Tiptap Editor

repository·v3·Indexed 41 days ago

https://github.com/ndtrung341/next-tiptap

A feature-rich WYSIWYG rich text editor for React and Next.js applications, built on Tiptap and Radix UI. Version 0.1.0 includes a TiptapEditor component with support for HTML/JSON output, custom extensions like CellAlign, Figcaption, and Figure, and a lowlightPlugin for lazy-loaded syntax highlighting.

Tokens
10.5K
Snippets
47
Records
53
Agent score
49%

What's inside Next Tiptap

  1. Install and run Next Tiptap Editor

    v3

    To use this project locally, clone the repository and install dependencies using your preferred package manager (pnpm, npm, or yarn).

    # Clone the repository
    git clone https://github.com/ndtrung341/next-tiptap.git
    
    # Navigate to project directory
    cd next-tiptap
    
    # Install dependencies
    pnpm install
    # or
    npm install
    # or
    yarn install
  2. Youtube extension attributes and HTML structure

    v3

    The Youtube extension manages a div wrapper containing an iframe.

    Attributes:

    • src: The embed URL of the video.
    • width: The width of the video, which is rendered as a percentage style (e.g., width: 100%).
    • height: The height of the video.
    • start: The timestamp to start the video.

    HTML Schema:

    • Input (parseHTML): The extension recognizes div iframe[src] elements.
    • Output (renderHTML): It renders a div containing an iframe with merged attributes.
  3. Customize editor styling with CSS variables

    v3

    The editor's dimensions can be customized using CSS variables in your globals.css file.

    :root {
      --rte-editor-min-height: 320px;
      --rte-editor-max-height: 640px;
      --rte-editor-max-width: 700px;
    }
  4. Manage Link menu state via LinkStorage

    v3

    The Link extension maintains a menuState within its storage to track the current UI mode. This state is useful for synchronizing external UI components (like a link popup or toolbar) with the editor's internal link state.

    Available LinkMenuState values:

    • "view": The user is currently interacting with an existing link.
    • "edit": The user is in the process of creating or modifying a link.
    • "hidden": The link menu is not active.
    export type LinkMenuState = "view" | "edit" | "hidden";
    
    export interface LinkStorage {
      menuState: LinkMenuState;
    }
  5. Implement the TiptapEditor component

    v3

    Import TiptapEditor and use a useRef with the TiptapEditorRef type to manage the editor instance. You can configure the output format, height constraints, and placeholder text via props.

    import TiptapEditor, { type TiptapEditorRef } from "@/components/tiptap-editor";
    import { useRef } from "react";
    
    export default function MyEditor() {
      const editorRef = useRef<TiptapEditorRef>(null);
    
      const handleChange = (content: string) => {
        console.log("Content updated:", content);
      };
    
      return (
        <TiptapEditor
          ref={editorRef}
          output="html"
          minHeight={320}
          maxHeight={640}
          onChange={handleChange}
          placeholder={{
            paragraph: "Start typing...",
            imageCaption: "Add a caption (optional)",
          }}
        />
      );
    }
  6. Extend the editor with custom Tiptap extensions

    v3

    To add or remove functionality, modify the createExtensions function located in src/components/tiptap-editor/extensions/index.ts.

    import { Extension } from "@tiptap/core";
    
    export const createExtensions = ({ placeholder }) => [
      // Add your custom extensions here
      StarterKit,
      Image,
      Link,
      Table,
      // ... more extensions
    ];
  7. Access the editor instance via ref

    v3

    Use the TiptapEditorRef to interact with the editor programmatically. You can retrieve content, check statistics, or execute commands.

    const editorRef = useRef<TiptapEditorRef>(null);
    
    // Get editor instance
    const editor = editorRef.current;
    
    // Get content
    const htmlContent = editor?.getHTML();
    const jsonContent = editor?.getJSON();
    
    // Get statistics
    const wordCount = editor?.storage.characterCount.words();
    const charCount = editor?.storage.characterCount.characters();
    
    // Programmatic control
    editor?.commands.setContent("<p>New content</p>");
    editor?.commands.focus();
  8. Configure the CellAlign extension

    v3

    The CellAlign extension allows you to control the vertical and horizontal alignment of table cells and headers. You can customize which node types are affected, which alignment values are permitted, and what the default alignment should be using the CellAlignOptions object.

    import CellAlign from './path-to/cell-align';
    
    CellAlign.configure({
      types: ['tableCell', 'tableHeader'],
      alignments: ['top', 'middle', 'bottom', 'middle-left', 'middle-right'],
      defaultAlignment: 'top-left'
    });
  9. Configure supported languages for lowlight

    v3

    The lowlight.config.ts file defines the default language and the mapping of supported languages used for syntax highlighting. Each supported language entry includes a human-readable name and a list of aliases that can be used to identify the language.

    • defaultLanguage: Defaults to "plaintext".
    • supportedLanguages: An object where keys are the language identifiers and values contain the name and aliases.
    export const defaultLanguage = "plaintext";
    
    export const supportedLanguages = {
      plaintext: {
        name: "Plain Text",
        aliases: ["plaintext", "text", "txt"],
      },
      javascript: {
        name: "JavaScript",
        aliases: ["javascript", "js", "jsx", "mjs", "cjs"],
      },
      // ... other languages
    };
  10. Configure Link extension options

    v3

    When initializing the Link extension, you can provide options to override the defaults. The extension includes the standard Tiptap Link options plus specific defaults for this implementation.

    Default options:

    • autolink: false (automatically converts URLs to links)
    • openOnClick: false (automatically opens the link on click)
    Link.configure({
      autolink: true,
      openOnClick: true,
    });