{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "migration-slate-to-plate-docs",
  "title": "From Slate to Plate",
  "description": "Move a Slate React editor to Plate's editor, plugin, and rendering model.",
  "files": [
    {
      "path": "../../content/docs/migration/slate-to-plate.mdx",
      "content": "---\ntitle: From Slate to Plate\ndescription: Move a Slate React editor to Plate's editor, plugin, and rendering model.\n---\n\nPlate keeps Slate's document model and moves editor setup, rendering, handlers,\nand command wiring into plugins. Migrate the editor shell first, then move\ncustom rendering and behavior into plugins.\n\n## Install\n\n```bash\nnpm install platejs\n```\n\nUse feature packages only for the nodes, marks, or behavior you add to the\neditor. Plate UI users should start with [Plate UI](/docs/installation/plate-ui)\ninstead of rebuilding every component by hand.\n\n## Migration Map\n\n| Slate surface | Plate surface |\n| --- | --- |\n| `createEditor()` plus `withReact()` | `usePlateEditor()` in React components, or `createPlateEditor()` in factories and tests. |\n| `<Slate>` plus `<Editable>` | `<Plate>` plus `<PlateContent>`. |\n| `renderElement` / `renderLeaf` switch statements | Plugin components through `.withComponent()` or `node.component`. |\n| `withX(editor)` plugin functions | `.overrideEditor()` for wrappers, `.extend*()` for new APIs and transforms. |\n| Top-level event handlers on `Editable` | Plugin `handlers` or `shortcuts`. |\n| `Transforms.*` imports | `editor.tf.*` transforms. |\n| `Editor.*` imports | `editor.api.*` queries. |\n\n## Editor Shell\n\nMove the editor value into the editor creation call and render the editable with `PlateContent`.\n\n```tsx title=\"components/editor.tsx\" showLineNumbers\n'use client';\n\nimport { Plate, PlateContent, usePlateEditor } from 'platejs/react';\n\nconst initialValue = [\n  {\n    children: [{ text: 'Hello Plate.' }],\n    type: 'p',\n  },\n];\n\nexport function Editor() {\n  const editor = usePlateEditor({\n    value: initialValue,\n  });\n\n  return (\n    <Plate editor={editor}>\n      <PlateContent className=\"p-4\" />\n    </Plate>\n  );\n}\n```\n\nUse `createPlateEditor()` when the editor is created outside React memoization.\n\n```ts title=\"lib/create-editor.ts\"\nimport { createPlateEditor } from 'platejs/react';\n\nexport const editor = createPlateEditor({\n  value: [\n    {\n      children: [{ text: 'Draft' }],\n      type: 'p',\n    },\n  ],\n});\n```\n\n## Custom Elements\n\nReplace `renderElement` branches with node plugins. Use `.withComponent()` when the only change is the React component.\n\n```tsx title=\"components/editor/paragraph-plugin.tsx\" showLineNumbers\nimport {\n  ParagraphPlugin,\n  PlateElement,\n  type PlateElementProps,\n} from 'platejs/react';\n\nexport function ParagraphElement({\n  children,\n  ...props\n}: PlateElementProps) {\n  return (\n    <PlateElement className=\"m-0 px-0 py-1\" {...props}>\n      {children}\n    </PlateElement>\n  );\n}\n\nexport const AppParagraphPlugin = ParagraphPlugin.withComponent(\n  ParagraphElement\n);\n```\n\nIf your Slate document stores a custom type like `paragraph`, keep that type on the plugin.\n\n```tsx title=\"components/editor/paragraph-plugin.tsx\" showLineNumbers\nexport const AppParagraphPlugin = ParagraphPlugin.configure({\n  node: { type: 'paragraph' },\n}).withComponent(ParagraphElement);\n```\n\n## Custom Behavior\n\nUse `.overrideEditor()` when the Slate plugin wrapped an existing editor method.\n\n```tsx title=\"components/editor/limit-exclamation-plugin.tsx\" showLineNumbers\nimport { createPlatePlugin } from 'platejs/react';\n\nexport const LimitExclamationPlugin = createPlatePlugin({\n  key: 'limitExclamation',\n}).overrideEditor(({ tf: { insertText } }) => ({\n  transforms: {\n    insertText(text, options) {\n      insertText(text === '!' ? '.' : text, options);\n    },\n  },\n}));\n```\n\nUse `.extendEditorApi()` or `.extendEditorTransforms()` when the plugin adds a new method.\n\n```tsx title=\"components/editor/signature-plugin.tsx\" showLineNumbers\nimport { createPlatePlugin } from 'platejs/react';\n\nexport const SignaturePlugin = createPlatePlugin({\n  key: 'signature',\n}).extendEditorTransforms(({ editor }) => ({\n  insertSignature() {\n    editor.tf.insertText(' - Plate');\n  },\n}));\n```\n\n## Handlers And Shortcuts\n\nMove editor events into the plugin that owns the behavior.\n\n```tsx title=\"components/editor/tab-plugin.tsx\" showLineNumbers\nimport { createPlatePlugin } from 'platejs/react';\n\nexport const TabPlugin = createPlatePlugin({\n  key: 'tab',\n  handlers: {\n    onKeyDown: ({ event }) => {\n      if (event.key !== 'Tab') return false;\n\n      event.preventDefault();\n\n      return true;\n    },\n  },\n});\n```\n\nUse `shortcuts` when the key combination should call a plugin API, transform, or explicit handler.\n\n```tsx title=\"components/editor/save-plugin.tsx\" showLineNumbers\nimport { createPlatePlugin } from 'platejs/react';\n\nexport const SavePlugin = createPlatePlugin({\n  key: 'save',\n}).extend({\n  shortcuts: {\n    draft: {\n      keys: 'mod+s',\n      handler: ({ event }) => {\n        event.preventDefault();\n\n        return true;\n      },\n    },\n  },\n});\n```\n\n## API Calls\n\nPlate keeps Slate-style direct methods for compatibility, but plugin code should use the namespaced API and transform surfaces.\n\n```ts title=\"editor-commands.ts\"\neditor.tf.toggleMark('bold');\neditor.tf.insertText('Hello');\n\nconst text = editor.api.string([]);\n\nif (editor.selection) {\n  const isStart = editor.api.isStart(editor.selection.anchor, []);\n}\n```\n\n## Headless Code\n\nUse `createSlateEditor` from `platejs` for non-React importers, serializers, transforms, and tests.\n\n```ts title=\"lib/headless-editor.ts\"\nimport { createSlateEditor } from 'platejs';\n\nexport const editor = createSlateEditor({\n  value: [\n    {\n      children: [{ text: 'Headless document.' }],\n      type: 'p',\n    },\n  ],\n});\n```\n\n## Related\n\n- [Editor](/docs/editor) for editor creation options.\n- [Plugin Components](/docs/plugin-components) for replacing `renderElement` and `renderLeaf`.\n- [Plugin Methods](/docs/plugin-methods) for `.configure()`, `.extend*()`, and `.overrideEditor()`.\n- [Plugin Shortcuts](/docs/plugin-shortcuts) for keyboard command wiring.\n",
      "type": "registry:file",
      "target": "content/docs/plate/migration/slate-to-plate.mdx"
    }
  ],
  "type": "registry:file"
}