Skip to main content

Overview

The paragraph extension adds support for paragraph nodes, which are the default block-level containers for inline content. Paragraphs are typically the most commonly used block type in rich text editors.

Installation

npm install @prosekit/extensions

Usage

import { defineParagraph } from '@prosekit/extensions/paragraph'
import { createEditor } from '@prosekit/core'

const extension = defineParagraph()
const editor = createEditor({ extension })

API Reference

defineParagraph()

Defines a paragraph node with commands, keymap, and node specification. This is the main function you’ll use to add paragraph support. Returns: ParagraphExtension This extension includes:
  • Node specification
  • Commands for manipulating paragraphs
  • Keyboard shortcuts

defineParagraphSpec()

Defines only the paragraph node specification without commands or keymaps. Returns: ParagraphSpecExtension

defineParagraphCommands()

Defines paragraph-related commands. Returns: ParagraphCommandsExtension

defineParagraphKeymap()

Defines keyboard shortcuts for paragraph operations. Returns: PlainExtension

Node Specification

The paragraph node is defined with the following properties:
  • name: paragraph
  • content: inline* (accepts zero or more inline nodes)
  • group: block
  • parseDOM: [{ tag: 'p' }]
  • toDOM: Renders as <p> element
  • priority: 4 (highest) - paragraphs are the default block node

Commands

setParagraph()

Converts the current block to a paragraph.
import { useEditor } from '@prosekit/react'

function ParagraphButton() {
  const editor = useEditor()
  
  const handleClick = () => {
    editor.commands.setParagraph()
  }
  
  return <button onClick={handleClick}>Paragraph</button>
}
Command signature:
setParagraph: []

Keyboard Shortcuts

ShortcutAction
Mod-Alt-0Convert current block to paragraph
Note: Mod is Cmd on macOS and Ctrl on Windows/Linux.

Examples

Basic Setup

import { createEditor } from '@prosekit/core'
import { union } from '@prosekit/core'
import { defineDoc } from '@prosekit/extensions/doc'
import { defineParagraph } from '@prosekit/extensions/paragraph'
import { defineText } from '@prosekit/extensions/text'

const extension = union([
  defineDoc(),
  defineParagraph(),
  defineText(),
])

const editor = createEditor({ extension })

Programmatically Setting Paragraphs

import { createEditor } from '@prosekit/core'
import { defineParagraph } from '@prosekit/extensions/paragraph'

const editor = createEditor({
  extension: defineParagraph(),
})

// Convert current selection to paragraph
editor.commands.setParagraph()

Custom Paragraph Button

import { useEditor } from '@prosekit/react'
import { Button } from './ui/button'

function ParagraphButton() {
  const editor = useEditor()
  
  const isActive = editor.nodes.paragraph.isActive()
  
  return (
    <Button
      onClick={() => editor.commands.setParagraph()}
      data-active={isActive}
    >
      Normal Text
    </Button>
  )
}

Reset to Paragraph After Heading

// Automatically convert heading to paragraph after pressing Enter
import { defineParagraph } from '@prosekit/extensions/paragraph'
import { defineHeading } from '@prosekit/extensions/heading'
import { union } from '@prosekit/core'

const extension = union([
  defineParagraph(),
  defineHeading(),
])

// The heading extension includes a Backspace handler that
// converts headings back to paragraphs when at the start

Styling

Paragraph nodes render as standard <p> HTML elements. You can style them with CSS:
.prosekit-editor p {
  margin-bottom: 1em;
  line-height: 1.6;
}

.prosekit-editor p:last-child {
  margin-bottom: 0;
}

HTML Structure

Input HTML:
<p>This is a paragraph.</p>
Output HTML:
<p>This is a paragraph.</p>
  • Text - Required for text content within paragraphs
  • Heading - Alternative block type for titles
  • Blockquote - For quoted text blocks
  • Code Block - For code snippets