{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "editor-docs",
  "title": "Editor Configuration",
  "description": "Learn how to configure and customize the Plate editor.",
  "files": [
    {
      "path": "../../content/docs/(guides)/editor.mdx",
      "content": "---\ntitle: Editor Configuration\ndescription: Learn how to configure and customize the Plate editor.\n---\n\nThis guide covers the configuration options for the Plate editor, including basic setup, plugin management, and advanced configuration techniques.\n\n## Basic Editor Configuration\n\nTo create a basic Plate editor, you can use the `createPlateEditor` function, or `usePlateEditor` in a React component:\n\n```ts\nimport { createPlateEditor } from 'platejs/react';\n\nconst editor = createPlateEditor({\n  plugins: [HeadingPlugin],\n});\n```\n\n### Initial Value\n\nSet the initial content of the editor:\n\n```ts\nconst editor = createPlateEditor({\n  value: [\n    {\n      type: 'p',\n      children: [{ text: 'Hello, Plate!' }],\n    },\n  ],\n});\n```\n\nYou can also initialize the editor with an HTML string and the associated plugins:\n\n```ts\nconst editor = createPlateEditor({\n  plugins: [BoldPlugin, ItalicPlugin],\n  value: '<p>This is <b>bold</b> and <i>italic</i> text!</p>',\n});\n```\n\nFor a comprehensive list of plugins that support HTML string deserialization, refer to the [Plugin Deserialization Rules](/docs/html#plugin-deserialization-rules) section.\n\n### Async Initial Value\n\nIf you need to fetch the initial value asynchronously (e.g., from an API), you can pass an async function directly to the `value` option:\n\n```tsx\nfunction AsyncEditor() {\n  const editor = usePlateEditor({\n    value: async () => {\n      // Simulate fetching data from an API\n      const response = await fetch('/api/document');\n      const data = await response.json();\n      return data.content;\n    },\n    autoSelect: 'end',\n    onReady: ({ editor, value }) => {\n      console.info('Editor ready with loaded value:', value);\n    },\n  });\n\n  if (!editor.children.length) return <div>Loading…</div>;\n\n  return (\n    <Plate editor={editor}>\n      <EditorContainer>\n        <Editor />\n      </EditorContainer>\n    </Plate>\n  );\n}\n```\n\n### Adding Plugins\n\nYou can add plugins to your editor by including them in the `plugins` array:\n\n```ts\nconst editor = createPlateEditor({\n  plugins: [HeadingPlugin, ListPlugin],\n});\n```\n\n### Max Length\n\nSet the maximum length of the editor:\n\n```ts\nconst editor = createPlateEditor({\n  maxLength: 100,\n});\n```\n\n## Advanced Configuration\n\n### Editor ID\n\nSet a custom id for the editor:\n\n```ts\nconst editor = createPlateEditor({\n  id: 'my-custom-editor-id',\n});\n```\n\nIf defined, you should always pass the `id` as the first argument in any editor retrieval methods.\n\n### Node ID\n\nPlate includes a built-in system for automatically assigning unique IDs to nodes, which is crucial for certain plugins and for data persistence strategies that rely on stable identifiers.\n\nThis feature is enabled by default. You can customize its behavior or disable it entirely through the `nodeId` option.\n\n#### Configuration\n\nTo configure Node ID behavior, pass an object to the `nodeId` property when creating your editor:\n\n```ts\nconst editor = usePlateEditor({\n  // ... other plugins and options\n  nodeId: {\n    // Function to generate IDs (default: nanoid(10))\n    idCreator: () => uuidv4(),\n\n    // Exclude inline elements from getting IDs (default: true)\n    filterInline: true, \n\n    // Exclude text nodes from getting IDs (default: true)\n    filterText: true,\n\n    // Reuse IDs on undo/redo and copy/paste if not in document (default: false)\n    // Set to true if IDs should be stable across such operations.\n    reuseId: false,\n\n    // Control initial-value ID assignment (default: 'if-needed')\n    // Use 'always' to fill every missing ID in the initial value.\n    initialValueIds: 'always',\n    \n    // Prevent overriding IDs when inserting nodes with an existing id (default: false)\n    disableInsertOverrides: false,\n\n    // Only allow specific node types to receive IDs (default: all)\n    allow: ['p', 'h1'], \n\n    // Exclude specific node types from receiving IDs (default: [])\n    exclude: ['code_block'],\n\n    // Custom filter function to determine if a node should get an ID\n    filter: ([node, path]) => {\n      // Example: Only ID on top-level blocks\n      return path.length === 1;\n    },\n  },\n});\n```\n\n<Callout type=\"note\">\n  The `NodeIdPlugin` (which handles this) is part of the core plugins and is automatically included. You only need to specify the `nodeId` option if you want to customize its default behavior.\n</Callout>\n\n#### Disabling Node IDs\n\nIf you don't need automatic node IDs, you can disable the feature:\n\n```ts\nconst editor = usePlateEditor({\n  // ... other plugins and options\n  nodeId: false, // This will disable the NodeIdPlugin\n});\n```\n\nBy disabling this, certain plugins that rely on node IDs will not function properly. The following plugins require block IDs to work:\n\n- **[Block Selection](/docs/block-selection)** - Needs IDs to track which blocks are selected\n- **[Block Menu](/docs/block-menu)** - Requires IDs to show context menus for specific blocks  \n- **[Drag & Drop](/docs/dnd)** - Uses IDs to identify blocks during drag operations\n- **[Table](/docs/table)** - Relies on IDs for cell selection\n- **[Table of Contents](/docs/toc)** - Needs heading IDs for navigation and scrolling\n- **[Toggle](/docs/toggle)** - Uses IDs to track which toggles are open/closed\n\n### Navigation Feedback\n\nPlate also includes a built-in navigation feedback plugin for \"you landed here\"\nUX after TOC jumps, footnote navigation, search jumps, and custom outline\nmovement.\n\nThis feature is enabled by default. You only need to touch the\n`navigationFeedback` option when you want to change the flash duration or turn\nthe plugin off.\n\n#### Configuration\n\n```ts\nconst editor = createPlateEditor({\n  navigationFeedback: {\n    duration: 1200,\n  },\n});\n```\n\n<Callout type=\"note\">\n  The `NavigationFeedbackPlugin` is part of the core plugins and is\n  automatically included. Use `navigationFeedback` for normal configuration and\n  keep `rootPlugin.configurePlugin(...)` for advanced escape-hatch work.\n</Callout>\n\n#### Disabling Navigation Feedback\n\n```ts\nconst editor = createPlateEditor({\n  navigationFeedback: false,\n});\n```\n\n### Normalization\n\nControl whether the editor should normalize its content on initialization:\n\n```ts\nconst editor = createPlateEditor({\n  shouldNormalizeEditor: true,\n});\n```\n\nNote that normalization may take a few dozen milliseconds for large documents, such as the playground value.\n\n### Auto-selection\n\nConfigure the editor to automatically select a range:\n\n```ts\nconst editor = createPlateEditor({\n  autoSelect: 'end', // or 'start', or true\n});\n```\n\nThis is not the same as auto-focus: you can select text without focusing the editor.\n\n### Component Overrides\n\nOverride default components for plugins:\n\n```ts\nconst editor = createPlateEditor({\n  plugins: [HeadingPlugin],\n  components: {\n    [ParagraphPlugin.key]: CustomParagraphComponent,\n    [HeadingPlugin.key]: CustomHeadingComponent,\n  },\n});\n```\n\n### Plugin Overrides\n\nOverride specific plugin configurations:\n\n```ts\nconst editor = createPlateEditor({\n  plugins: [HeadingPlugin],\n  override: {\n    plugins: {\n      [ParagraphPlugin.key]: {\n        options: {\n          customOption: true,\n        },\n      },\n    },\n  },\n});\n```\n\n### Disable Plugins\n\nDisable specific plugins:\n\n```ts\nconst editor = createPlateEditor({\n  plugins: [HeadingPlugin, ListPlugin],\n  override: {\n    enabled: {\n      [HistoryPlugin.key]: false,\n    },\n  },\n});\n```\n\n### Overriding Plugins\n\nYou can override core plugins or previously defined plugins by adding a plugin with the same key. The last plugin with a given key wins:\n\n```ts\nconst CustomParagraphPlugin = createPlatePlugin({\n  key: 'p',\n  // Custom implementation\n});\n\nconst editor = createPlateEditor({\n  plugins: [CustomParagraphPlugin],\n});\n```\n\n### Root Plugin\n\nFrom the root plugin, you can configure any plugin:\n\n```ts\nconst editor = createPlateEditor({\n  plugins: [HeadingPlugin],\n  rootPlugin: (plugin) =>\n    plugin.configurePlugin(LengthPlugin, {\n    options: {\n        maxLength: 100,\n      },\n    }),\n});\n```\n\n## Typed Editor\n\n`createPlateEditor` will automatically infer the types for your editor from the value and the plugins you pass in. For explicit type creation, use the generics:\n\n### Plugins Type\n\n```ts\nconst editor = createPlateEditor<Value, typeof TablePlugin | typeof LinkPlugin>({\n  plugins: [TablePlugin, LinkPlugin],\n});\n\n// Usage\neditor.tf.insert.tableRow()\n```\n\n### Value Type\n\nFor more complex editors, you can define your types in a separate file (e.g., `plate-types.ts`):\n\n```ts\nimport type { TElement, TText } from 'platejs';\nimport type { TPlateEditor } from 'platejs/react';\n\n// Define custom element types\ninterface ParagraphElement extends TElement {\n  align?: 'left' | 'center' | 'right' | 'justify';\n  children: RichText[];\n  type: typeof ParagraphPlugin.key;\n}\n\ninterface ImageElement extends TElement {\n  children: [{ text: '' }]\n  type: typeof ImagePlugin.key;\n  url: string;\n}\n\n// Define custom text types\ninterface FormattedText extends TText {\n  bold?: boolean;\n  italic?: boolean;\n}\n\nexport type MyRootBlock = ParagraphElement | ImageElement;\n\n// Define the editor's value type\nexport type MyValue = MyRootBlock[];\n\n// Define the custom editor type\nexport type MyEditor = TPlateEditor<MyValue, typeof TablePlugin | typeof LinkPlugin>;\n\nexport const useMyEditorRef = () => useEditorRef<MyEditor>();\n\n// Usage\nconst value: MyValue = [{\n  type: 'p',\n  children: [{ text: 'Hello, Plate!' }],\n}]\n\nconst editorInferred = createPlateEditor({\n  plugins: [TablePlugin, LinkPlugin],\n  value,\n});\n\n// or \nconst editorExplicit = createPlateEditor<MyValue, typeof TablePlugin | typeof LinkPlugin>({\n  plugins: [TablePlugin, LinkPlugin],\n  value,\n});\n```\n",
      "type": "registry:file",
      "target": "content/docs/plate/(guides)/editor.mdx"
    }
  ],
  "type": "registry:file"
}