---
title: Getting Started
description: A quick tutorial to get you up and running with Plate.
---

<Steps>

### Create project

You can choose one of the following templates to get started:

| Option                                                                            | Plate | Plugins | AI  | Backend |
| --------------------------------------------------------------------------------- | ----- | ------- | --- | ------- |
| [Notion-like template](https://pro.platejs.org/docs/templates/potion)             | ✅    | ✅      | ✅  | ✅      |
| [Plate playground template](https://github.com/udecode/plate-playground-template) | ✅    | ✅      | ✅  |         |
| [Plate minimal template](https://github.com/udecode/plate-template)               | ✅    |         |     |         |

For an existing React project, jump to the next step.

### Add dependencies

First, install the core dependencies:

```bash
npm install @udecode/plate-common slate slate-dom slate-react slate-history
```

For the examples in this guide, we'll also use these plugins:

```bash
npm install @udecode/plate-basic-marks @udecode/plate-heading @udecode/plate-block-quote @udecode/cn
```

- `@udecode/plate-basic-marks` provides bold, italic, underline, and code formatting.
- `@udecode/plate-heading` adds h1-h6 support.
- `@udecode/plate-block-quote` adds blockquote support.
- `@udecode/cn` helps with component styling (optional).

### Basic Editor

Let's start with a minimal editor setup.

```tsx showLineNumbers {1-5,11-13}
import {
  usePlateEditor,
  Plate,
  PlateContent,
} from '@udecode/plate-common/react';

export default function BasicEditor() {
  const editor = usePlateEditor();

  return (
    <Plate editor={editor}>
      <PlateContent placeholder="Type..." />
    </Plate>
  );
}
```

`Plate` manages the editor state and `PlateContent` renders the editor content.

<ComponentPreview name="basic-editor-default-demo" padding="md" />

### Styling

Let's give our editor some styles: [Editor](/docs/components/editor) is a styled version of `PlateContent`.

<ComponentPreview name="basic-editor-styling-demo" padding="md" />

To keep things simple, we'll continue to use `PlateContent` in the following code snippets.

<Callout className="mt-4">
  **Note**: `Editor` is just an example of a styled editor using Tailwind, and
  if you're using it, make sure to follow the installation steps in the [Manual
  Installation](/docs/components/installation/manual) guide. You can create your
  own styled version of `PlateContent`.
  <ComponentSource name="editor" />
</Callout>

### Initializing Editor's Value

Let's specify the initial content of the editor: a single paragraph.

```tsx showLineNumbers {3-12,16}
// ...

const value = [
  {
    type: 'p',
    children: [
      {
        text: 'This is editable plain text with react and history plugins, just like a <textarea>!',
      },
    ],
  },
];

export default function BasicEditor() {
  const editor = usePlateEditor({
    value,
  });

  return (
    <Plate editor={editor}>
      <PlateContent />
    </Plate>
  );
}
```

<Callout className="mt-4">
  **Note**: Plate uses the **`type`** property to enable plugins to render nodes
  by type.
</Callout>

<ComponentPreview name="basic-editor-value-demo" padding="md" />

### Implementing Change Handler

At this stage, it's crucial to monitor editor modifications in order to store the values appropriately. The **`onChange`** prop will serve this purpose. You can also persist the editor's state by saving the value to local storage or a database and loading it back when needed.

```tsx showLineNumbers {4-5,8,14-17}
// ...

export default function BasicEditor() {
  const localValue =
    typeof window !== 'undefined' && localStorage.getItem('editorContent');

  const editor = usePlateEditor({
    value: localValue ? JSON.parse(localValue) : value,
  });

  return (
    <Plate
      editor={editor}
      onChange={({ value }) => {
        // For performance, debounce your saving logic
        localStorage.setItem('editorContent', JSON.stringify(value));
      }}
    >
      <PlateContent />
    </Plate>
  );
}
```

<ComponentPreview name="basic-editor-handler-demo" padding="md" />

### Plugins

<Callout className="my-4">
  See the full list of plugins in the [Plugins](/docs/plugins) section.
</Callout>

Let's use a few basic plugins.

```tsx showLineNumbers {3-9,17-23}
// ...

import {
  BoldPlugin,
  ItalicPlugin,
  UnderlinePlugin,
} from '@udecode/plate-basic-marks/react';
import { HeadingPlugin } from '@udecode/plate-heading/react';
import { BlockquotePlugin } from '@udecode/plate-block-quote/react';

const value = [
  // ...
];

export default function BasicEditor() {
  const editor = usePlateEditor({
    plugins: [
      HeadingPlugin,
      BlockquotePlugin,
      BoldPlugin,
      ItalicPlugin,
      UnderlinePlugin,
    ],
    value,
  });

  return (
    <Plate editor={editor}>
      <PlateContent />
    </Plate>
  );
}
```

<ComponentPreview name="basic-plugins-default-demo" padding="md" />

The plugins are functioning correctly. However, since we haven't specified any custom components for rendering, the editor is using the default (unstyled) components. Specifically, the default element component is a **`div`**, and the default leaf component is a **`span`**.

<Callout className="mt-4">
  **Note**: You don't need to add core plugins such as **`ReactPlugin`**,
  **`HistoryPlugin`** and **`ParagraphPlugin`** as **`usePlateEditor`** already
  does it.
</Callout>

### Components

<Callout className="mt-4">
  **Note**: Plate plugins are packaged unstyled, implying that you have complete
  control over markup and styling, hence you can integrate your own design
  system or [Plate UI](/docs/components).
</Callout>

To plug-in all the components in one place, use the **`override.components`** option in **`usePlateEditor`**. We'll use the **`withProps`** helper to pass additional props to the components with Tailwind CSS classes.

```tsx showLineNumbers {3,6-7,20-47}
// ...

import { withProps } from '@udecode/cn';
import {
  Plate,
  PlateElement,
  PlateLeaf,
  usePlateEditor,
} from '@udecode/plate-common/react';

export default function BasicEditor() {
  const editor = usePlateEditor({
    plugins: [
      HeadingPlugin,
      BlockquotePlugin,
      BoldPlugin,
      ItalicPlugin,
      UnderlinePlugin,
    ],
    override: {
      components: {
        blockquote: withProps(PlateElement, {
          as: 'blockquote',
          className: 'mb-4 border-l-4 border-[#d0d7de] pl-4 text-[#636c76]',
        }),
        bold: withProps(PlateLeaf, { as: 'strong' }),
        h1: withProps(PlateElement, {
          as: 'h1',
          className:
            'mb-4 mt-6 text-3xl font-semibold tracking-tight lg:text-4xl',
        }),
        h2: withProps(PlateElement, {
          as: 'h2',
          className: 'mb-4 mt-6 text-2xl font-semibold tracking-tight',
        }),
        h3: withProps(PlateElement, {
          as: 'h3',
          className: 'mb-4 mt-6 text-xl font-semibold tracking-tight',
        }),
        italic: withProps(PlateLeaf, { as: 'em' }),
        p: withProps(PlateElement, {
          as: 'p',
          className: 'mb-4',
        }),
        underline: withProps(PlateLeaf, { as: 'u' }),
      },
    },
  });

  return (
    <Plate editor={editor}>
      <PlateContent />
    </Plate>
  );
}
```

<ComponentPreview name="basic-plugins-components-demo" padding="md" />

### Initializing Editor's Value with HTML String

You can also specify the initial content of the editor using an HTML string and the corresponding plugins.

```tsx showLineNumbers {3,8}
// ...

const htmlValue = '<p>This is <b>bold</b> and <i>italic</i> text!</p>';

export default function BasicEditor() {
  const editor = usePlateEditor({
    // ...
    value: htmlValue,
  });

  return (
    <Plate editor={editor}>
      <PlateContent />
    </Plate>
  );
}
```

### That's it!

You can now play around with the [Playground](/#playground) and start building your own editor.

</Steps>
