How to enforce first Node to be heading H1 in tiptap editor?

2.9k Views Asked by At

I am building a simple rich text editor for writing blogs. I want to enforce that first Node always be the title (h1 tag) which user should not be able to delete!

Is there a way to achieve this?

4

There are 4 best solutions below

0
On

If you're using React, and you don't want to use a custom document as mentioned by @pkid169 or default content, you can use a useEffect hook to set a heading to the editor.

Here's an example:

'use client'

import { EditorContent, useEditor } from '@tiptap/react'
import { StarterKit } from '@tiptap/starter-kit'
import { useState, useEffect } from 'react'

export default function HeaderBlock() {
  const [content, setContent] = useState('')

  const editor = useEditor({
    content,
    editorProps: {
      attributes: {
        class: '...'
      }
    },
    onUpdate: ({ editor }) => {
      setContent(editor?.getText() ?? '')
    },
    extensions: [
      StarterKit,
    ]
  })

  useEffect(() => {
    editor?.commands.setHeading({ level: 1 })
  })

  return (
    <EditorContent editor={editor}/>
  )
}
0
On

You could put it in content when initializing:

const editor = useEditor({
  extensions: [
    StarterKit.configure({
      heading: {
        levels: [1, 2],
      },
    }),
    Dropcursor.configure({
      color: "#4B5563",
    }),
    Placeholder.configure({
      showOnlyWhenEditable: true,
      placeholder: "Write something or press Enter to add a new block",
    }),
    CodeBlockLowlight.configure({
      lowlight,
    }),
    TaskList,
    CustomTaskItem,
    ListItem,
    Blockquote,
    CustomOrderedList,
    CustomHorizontalRule,
    Table.configure({
      resizable: true,
    }),
    TableRow,
    TableHeader,
    TableCell,
  ],
  editorProps: {
    attributes: {
      class: "focus:outline-none subpixel-antialiased",
    },
  },
  autofocus: true,

  // THIS
  content: `
    <h1>Hello there </h1>
  `,
})
0
On

You can achieve this via Custom Document, where you can define the document structure. Tip tap has an example page here https://tiptap.dev/examples/custom-document.

0
On

Extend Document:

const CustomDocument = Document.extend({
  // https://tiptap.dev/api/schema#content
  content: 'heading block*',
})

Load the CustomDocument and add default placeholder for Heading:

  new Editor({
    extensions: [
      CustomDocument,
      Placeholder.configure({
        placeholder: ({ node }) => {
          if (node.type.name === 'heading' && node.attrs.level == 1) {
            return 'H1 placeholder here';
          }
        },
      }),
    ]
  })

After that, you have to find a solution for prevent bold/italic/H2/H3/etc. on your H1. If you have a solution for it, please give the solution in comment.