> ## Documentation Index
> Fetch the complete documentation index at: https://docs.yoopta.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Paragraph

> Basic text blocks for content creation

export const PluginPlayground = ({pluginSlug, height = 420}) => {
  const baseUrl = 'https://yoopta.dev';
  return <div className="not-prose my-6 rounded-xl border border-zinc-200 dark:border-zinc-800 overflow-hidden">
      <iframe title={`${pluginSlug} plugin demo`} src={`${baseUrl}/playground/plugin/${pluginSlug}`} className="w-full border-0 bg-white dark:bg-zinc-900" style={{
    height: typeof height === 'number' ? `${height}px` : height
  }} />
    </div>;
};

## Overview

The Paragraph plugin is the fundamental building block of any document. It provides basic text formatting and should always be included in your editor configuration.

<PluginPlayground pluginSlug="paragraph" height={280} />

## Installation

```bash theme={null}
npm install @yoopta/paragraph
```

## Basic Usage

Pass the plugin to `createYooptaEditor`; do not pass `plugins` to `<YooptaEditor>`.

```jsx theme={null}
import { useMemo } from 'react';
import YooptaEditor, { createYooptaEditor } from '@yoopta/editor';
import Paragraph from '@yoopta/paragraph';

const plugins = [Paragraph];

export default function Editor() {
  const editor = useMemo(() => createYooptaEditor({ plugins, marks: [] }), []);
  return <YooptaEditor editor={editor} onChange={() => {}} />;
}
```

## Features

* **Plain Text**: Write unformatted text
* **Text Marks**: Supports bold, italic, underline, etc.
* **Alignment**: Left, center, right alignment
* **Keyboard Shortcuts**: Type `p` or `text` to insert
* **Default Block**: Typically the default block type
* **Indentation**: Support for nested indentation

## Configuration

The Paragraph plugin works out of the box with minimal configuration:

```jsx theme={null}
import { Paragraph } from '@yoopta/paragraph';

const plugins = [Paragraph];
```

## Options

<ResponseField name="display" type="object">
  <Expandable title="properties">
    <ResponseField name="title" type="string" default="Text">
      Display title in UI menus
    </ResponseField>

    <ResponseField name="description" type="string">
      Description shown in menus
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="shortcuts" type="string[]" default="['p', 'text']">
  Keyboard shortcuts to trigger the plugin
</ResponseField>

## Commands

Use the **`Blocks`** namespace from `@yoopta/editor`:

```typescript theme={null}
import { Blocks } from '@yoopta/editor';

// Transform current block to a Paragraph block
Blocks.toggleBlock(editor, 'Paragraph', { preserveContent: true });

// Insert a new paragraph block
Blocks.insertBlock(editor, 'Paragraph', { at: editor.path.current, focus: true });

// Update paragraph alignment (block meta)
Blocks.updateBlock(editor, blockId, {
  meta: { align: 'center' },
});
```

## Custom Rendering

```jsx theme={null}
import { Paragraph } from '@yoopta/paragraph';

const CustomParagraph = Paragraph.extend({
  elements: {
    paragraph: {
      render: (props) => {
        return (
          <p className="custom-paragraph" {...props.attributes}>
            {props.children}
          </p>
        );
      },
    },
  },
});
```

### With Custom Styling

```jsx theme={null}
const StyledParagraph = Paragraph.extend({
  elements: {
    paragraph: {
      render: (props) => {
        const align = props.blockData?.meta?.align || 'left';

        return (
          <p className={`paragraph-${align}`} style={{ textAlign: align }} {...props.attributes}>
            {props.children}
          </p>
        );
      },
    },
  },
});
```

## Parsers

### HTML Deserialization

The plugin automatically deserializes `<p>` tags:

```html theme={null}
<p>This is a paragraph with <strong>bold</strong> and <em>italic</em> text.</p>
```

### HTML Serialization

```html theme={null}
<p data-meta-align="left" data-meta-depth="0">Your paragraph content</p>
```

### Markdown Serialization

```markdown theme={null}
Your paragraph content
```

### Email Serialization

The plugin provides email-compatible HTML with inline styles:

```html theme={null}
<table style="width: 100%">
  <tbody>
    <tr>
      <td>
        <p style="font-size: 16px; line-height: 1.75rem; margin: .5rem 0">Your paragraph content</p>
      </td>
    </tr>
  </tbody>
</table>
```

## Text Marks

The Paragraph plugin supports all standard text marks:

* **Bold**: Ctrl/Cmd + B
* **Italic**: Ctrl/Cmd + I
* **Underline**: Ctrl/Cmd + U
* **Strikethrough**: Ctrl/Cmd + Shift + S
* **Code**: Ctrl/Cmd + E
* **Links**: Ctrl/Cmd + K

## Block Metadata

Each paragraph block can have metadata:

```typescript theme={null}
{
  align: 'left' | 'center' | 'right',
  depth: number, // Indentation level
}
```

## Use Cases

<CardGroup cols={2}>
  <Card title="Blog Posts">Main body text for articles and posts</Card>
  <Card title="Documentation">Descriptive text in technical docs</Card>
  <Card title="Landing Pages">Marketing copy and descriptions</Card>
  <Card title="Notes">Quick notes and text entries</Card>
</CardGroup>

## Best Practices

<AccordionGroup>
  <Accordion title="Always Include Paragraph">
    The Paragraph plugin should always be included as it's typically the default block type
  </Accordion>

  <Accordion title="Use as Default">
    Configure Paragraph as the default block type for new content
  </Accordion>

  <Accordion title="Keep It Simple">
    The Paragraph plugin should remain simple - use other plugins for complex formatting
  </Accordion>

  <Accordion title="Combine with Marks">
    Use text marks (bold, italic) for inline formatting within paragraphs
  </Accordion>
</AccordionGroup>

## Extensions

The Paragraph plugin includes custom Slate extensions for normalized behavior:

### withParagraph

```typescript theme={null}
import { withParagraph } from '@yoopta/paragraph';

// Applied automatically by the plugin
const slate = withParagraph(createEditor());
```

This extension handles:

* Text normalization
* Empty paragraph handling
* Consistent whitespace behavior

## Advanced Patterns

### With Drop Caps

```jsx theme={null}
const DropCapParagraph = Paragraph.extend({
  elements: {
    paragraph: {
      render: (props) => {
        const hasDropCap = props.element.props?.dropCap;

        return (
          <p className={hasDropCap ? 'drop-cap' : ''} {...props.attributes}>
            {props.children}
          </p>
        );
      },
    },
  },
});
```

```css theme={null}
.drop-cap::first-letter {
  float: left;
  font-size: 3em;
  line-height: 0.9;
  margin: 0 0.1em 0 0;
}
```

### With Character Count

```jsx theme={null}
const CountedParagraph = Paragraph.extend({
  elements: {
    paragraph: {
      render: (props) => {
        const text = props.element.children.map((n) => n.text).join('');
        const count = text.length;

        return (
          <div className="paragraph-wrapper">
            <p {...props.attributes}>{props.children}</p>
            <span className="char-count">{count} characters</span>
          </div>
        );
      },
    },
  },
});
```

## Related Plugins

* [Headings Plugin](/plugins/headings) - For titles and headings
* [Blockquote Plugin](/plugins/blockquote) - For quoted text
* [Code Plugin](/plugins/code) - For code blocks
