Slate types custom document models through editor value generics. Define the
element and text shapes for your editor, create a Value from the element
union, then pass that value to createEditor<Value>() or
useSlateEditor<Value>() when React owns the editor lifetime.
Defining Element And Text Types
import { type ElementOf, type TextOf, type ValueOf } from "@platejs/slate";
import { useSlateEditor, type ReactEditor } from "@platejs/slate-react";
type CustomText = { text: string; bold?: true };
type ParagraphElement = {
type: "paragraph";
children: CustomText[];
};
type HeadingElement = {
type: "heading";
level: number;
children: CustomText[];
};
type CustomValue = (ParagraphElement | HeadingElement)[];
type CustomEditor = ReactEditor<CustomValue>;
const useCustomEditor = () => {
const editor = useSlateEditor<CustomValue>();
type CustomElement = ElementOf<typeof editor>;
type EditorText = TextOf<typeof editor>;
type EditorValue = ValueOf<typeof editor>;
return editor;
};import { type ElementOf, type TextOf, type ValueOf } from "@platejs/slate";
import { useSlateEditor, type ReactEditor } from "@platejs/slate-react";
type CustomText = { text: string; bold?: true };
type ParagraphElement = {
type: "paragraph";
children: CustomText[];
};
type HeadingElement = {
type: "heading";
level: number;
children: CustomText[];
};
type CustomValue = (ParagraphElement | HeadingElement)[];
type CustomEditor = ReactEditor<CustomValue>;
const useCustomEditor = () => {
const editor = useSlateEditor<CustomValue>();
type CustomElement = ElementOf<typeof editor>;
type EditorText = TextOf<typeof editor>;
type EditorValue = ValueOf<typeof editor>;
return editor;
};Annotating Initial Values
Annotate the editor's initial value with your value type.
import { Editable, Slate, useSlateEditor } from "@platejs/slate-react";
type CustomText = { text: string; bold?: true };
type ParagraphElement = { type: "paragraph"; children: CustomText[] };
type CustomValue = ParagraphElement[];
const initialValue: CustomValue = [
{
type: "paragraph",
children: [{ text: "A line of text in a paragraph." }],
},
];
const App = () => {
const editor = useSlateEditor<CustomValue>({ initialValue });
return (
<Slate editor={editor}>
<Editable />
</Slate>
);
};import { Editable, Slate, useSlateEditor } from "@platejs/slate-react";
type CustomText = { text: string; bold?: true };
type ParagraphElement = { type: "paragraph"; children: CustomText[] };
type CustomValue = ParagraphElement[];
const initialValue: CustomValue = [
{
type: "paragraph",
children: [{ text: "A line of text in a paragraph." }],
},
];
const App = () => {
const editor = useSlateEditor<CustomValue>({ initialValue });
return (
<Slate editor={editor}>
<Editable />
</Slate>
);
};Working With Nodes
Use exported helper types to derive the document types from an editor instead of duplicating unions at every call site.
import type { ElementOf, TextOf, ValueOf } from "@platejs/slate";
type CustomElement = ElementOf<typeof editor>;
type CustomText = TextOf<typeof editor>;
type CustomValue = ValueOf<typeof editor>;import type { ElementOf, TextOf, ValueOf } from "@platejs/slate";
type CustomElement = ElementOf<typeof editor>;
type CustomText = TextOf<typeof editor>;
type CustomValue = ValueOf<typeof editor>;When reading a generic Node, narrow it before accessing element-specific
properties.
import { ElementApi, type Node } from "@platejs/slate";
const isParagraph = (node: Node) =>
ElementApi.isElement(node) && node.type === "paragraph";import { ElementApi, type Node } from "@platejs/slate";
const isParagraph = (node: Node) =>
ElementApi.isElement(node) && node.type === "paragraph";Multiple Document Models
Use a different Value type for each editor model.
const articleEditor = createEditor<ArticleValue>();
const commentEditor = createEditor<CommentValue>();const articleEditor = createEditor<ArticleValue>();
const commentEditor = createEditor<CommentValue>();Each editor carries its value through ValueOf<typeof editor>,
ElementOf<typeof editor>, and TextOf<typeof editor>.