Skip to main content

Overview

The hard-break extension adds support for hard line break nodes, which insert line breaks (<br>) within text blocks without creating a new paragraph. This is useful for addresses, poetry, or any content where you need line breaks within a single block.

Installation

npm install @prosekit/extensions

Usage

import { defineHardBreak } from '@prosekit/extensions/hard-break'
import { createEditor } from '@prosekit/core'

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

API Reference

defineHardBreak()

Defines a hard break node with commands, keymap, and node specification. Returns: HardBreakExtension This extension includes:
  • Node specification
  • Insert command
  • Keyboard shortcuts

defineHardBreakSpec()

Defines only the hard break node specification. Returns: HardBreakSpecExtension

defineHardBreakCommands()

Defines hard break-related commands. Returns: HardBreakCommandsExtension

defineHardBreakKeymap()

Defines keyboard shortcuts for inserting hard breaks. Returns: PlainExtension

insertHardBreak()

Returns a command that inserts a hard break at the current selection. Returns: Command
import { insertHardBreak } from '@prosekit/extensions/hard-break'

const command = insertHardBreak()

Node Specification

The hard break node is defined with the following properties:
  • name: hardBreak
  • inline: true (exists within text content)
  • selectable: false (cannot be selected)
  • group: inline
  • leafText: Returns \n (represents as newline in plain text)
  • parseDOM: [{ tag: 'br' }]
  • toDOM: Renders as <br> element

Commands

insertHardBreak()

Inserts a hard break (line break) at the current cursor position.
import { useEditor } from '@prosekit/react'

function HardBreakButton() {
  const editor = useEditor()
  
  return (
    <button onClick={() => editor.commands.insertHardBreak()}>
      Line Break
    </button>
  )
}
Command signature:
insertHardBreak: []

Keyboard Shortcuts

ShortcutAction
Mod-EnterInsert hard break
Shift-EnterInsert hard break
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 { defineHardBreak } from '@prosekit/extensions/hard-break'
import { defineText } from '@prosekit/extensions/text'

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

const editor = createEditor({ extension })

Insert Button

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

function LineBreakButton() {
  const editor = useEditor()
  
  return (
    <Button
      onClick={() => editor.commands.insertHardBreak()}
      aria-label="Insert line break"
    >
      <CornerDownLeftIcon /> Break
    </Button>
  )
}

Poetry or Addresses

import { useEditor } from '@prosekit/react'

function AddressField() {
  const editor = useEditor()
  
  return (
    <div>
      <label>Address:</label>
      <div className="editor">
        {/* User types: */}
        {/* John Doe<Shift-Enter> */}
        {/* 123 Main St<Shift-Enter> */}
        {/* City, State 12345 */}
      </div>
    </div>
  )
}

Programmatic Insertion

const editor = useEditor()

// Insert line breaks programmatically
editor.commands.insertText('Line 1')
editor.commands.insertHardBreak()
editor.commands.insertText('Line 2')
editor.commands.insertHardBreak()
editor.commands.insertText('Line 3')

Custom Behavior

import { useEditor } from '@prosekit/react'
import { useCallback } from 'react'

function CustomEditor() {
  const editor = useEditor()
  
  const handleKeyDown = useCallback((event: React.KeyboardEvent) => {
    // Custom logic: always insert hard break on Enter
    if (event.key === 'Enter') {
      event.preventDefault()
      editor.commands.insertHardBreak()
    }
  }, [editor])
  
  return <div onKeyDown={handleKeyDown}>{/* editor */}</div>
}

Use Cases

Addresses

John Smith
123 Main Street
Apt 4B
New York, NY 10001

Poetry

Roses are red,
Violets are blue,
Hard breaks are useful,
For poetry too.

Code Examples

Step 1: Open the file
Step 2: Edit the content
Step 3: Save the changes

Contact Information

Email: john@example.com
Phone: (555) 123-4567
Fax: (555) 123-4568

Styling

Hard breaks render as standard <br> elements and don’t typically need styling:
/* If you want to visualize line breaks in the editor */
.prosekit-editor br::after {
  content: '↵';
  color: #ccc;
  font-size: 0.75em;
}

/* Only show in edit mode */
.prosekit-editor[contenteditable="true"] br::after {
  content: '↵';
}

HTML Structure

Input HTML:
<p>Line 1<br>Line 2<br>Line 3</p>
Output HTML:
<p>Line 1<br>Line 2<br>Line 3</p>

Behavior

vs. Paragraphs

Understand the difference between hard breaks and paragraphs:
// Hard break (single block):
// <p>Line 1<br>Line 2</p>

// Two paragraphs (two blocks):
// <p>Line 1</p>
// <p>Line 2</p>

Plain Text Export

When converting to plain text, hard breaks become newline characters (\n):
const text = editor.getText()
// "Line 1\nLine 2\nLine 3"

Selection

Hard breaks are not selectable nodes (unlike horizontal rules). The cursor moves past them naturally as you navigate text.

Accessibility

Hard breaks are semantic HTML:
  • Screen readers treat <br> as a line break pause
  • Use for meaningful line breaks, not layout spacing
  • Consider using CSS margins/padding for visual spacing instead

Common Patterns

Preventing Hard Breaks in Headings

import { defineHeading } from '@prosekit/extensions/heading'
import { defineHardBreak } from '@prosekit/extensions/hard-break'
import { union } from '@prosekit/core'

// Hard breaks work in all inline content by default
const extension = union([
  defineHeading(),
  defineHardBreak(),
])

// To prevent hard breaks in specific nodes,
// you would need custom node specs

Alternative: Shift+Enter Behavior

By default, Shift+Enter inserts a hard break. This is a common convention:
  • Enter → New paragraph
  • Shift+Enter → Line break within paragraph
  • Paragraph - Blocks containing hard breaks
  • Text - Text content around hard breaks
  • Heading - May contain hard breaks