A hyperscript helper for creating Slate documents with JSX-like syntax.
npx @tessl/cli install tessl/npm-slate-hyperscript@0.115.0Slate Hyperscript provides a hyperscript helper for creating Slate documents with JSX-like syntax. It enables developers to programmatically generate Slate editor content using a familiar JSX-style API, making it easier to create complex document structures, test Slate-based editors, and work with Slate's data model.
npm install slate-hyperscriptimport {
jsx,
createHyperscript,
createEditor,
createText,
HyperscriptCreators,
HyperscriptShorthands,
Token,
AnchorToken,
FocusToken,
addAnchorToken,
addFocusToken,
getAnchorOffset,
getFocusOffset
} from "slate-hyperscript";For CommonJS:
const {
jsx,
createHyperscript,
createEditor,
createText,
HyperscriptCreators,
HyperscriptShorthands,
Token,
AnchorToken,
FocusToken,
addAnchorToken,
addFocusToken,
getAnchorOffset,
getFocusOffset
} = require("slate-hyperscript");/** @jsx jsx */
import { jsx } from "slate-hyperscript";
// Create a simple editor with text content
const editor = (
<editor>
<element>
Hello <text bold>world</text>!
</element>
</editor>
);
// Create elements with selections
const editorWithSelection = (
<editor>
<element>
w<anchor />or<focus />d
</element>
</editor>
);
// Create nested elements
const nestedEditor = (
<editor>
<element type="paragraph">
<element type="bold">Bold text</element>
Regular text
</element>
</editor>
);Slate Hyperscript is built around several key components:
jsx function that processes JSX elements into Slate objectsThe pre-configured hyperscript function that creates Slate objects from JSX elements.
/**
* The default hyperscript factory that ships with Slate, without custom tags.
*/
const jsx: <S extends string>(
tagName: S,
attributes?: Object,
...children: any[]
) => any;Usage Example:
/** @jsx jsx */
import { jsx } from "slate-hyperscript";
// Basic element creation
const element = <element>Hello world</element>;
// Text with formatting
const formattedText = <text bold italic>Important text</text>;
// Complete editor
const editor = (
<editor>
<element>Content goes here</element>
</editor>
);Factory function for creating custom hyperscript functions with specialized creators and element shortcuts.
/**
* Create a Slate hyperscript function with custom options
* @param options - Configuration object
* @returns Custom hyperscript function
*/
function createHyperscript(options?: {
creators?: HyperscriptCreators;
elements?: HyperscriptShorthands;
}): <S extends string>(
tagName: S,
attributes?: Object,
...children: any[]
) => any;
/**
* Dictionary of creator functions keyed by tag name
*/
type HyperscriptCreators<T = any> = Record<
string,
(tagName: string, attributes: { [key: string]: any }, children: any[]) => T
>;
/**
* Dictionary of properties applied to specific element types, keyed by tag name
*/
type HyperscriptShorthands = Record<string, Record<string, any>>;Usage Example:
import { createHyperscript } from "slate-hyperscript";
// Create hyperscript with custom element shortcuts
const jsx = createHyperscript({
elements: {
paragraph: { type: "paragraph" },
heading: { type: "heading", level: 1 },
},
});
// Now you can use custom tags
const content = (
<editor>
<heading>My Title</heading>
<paragraph>Some content</paragraph>
</editor>
);Higher-order functions for creating specific Slate objects outside of JSX context.
/**
* Create a top-level Editor object creator
* @param makeEditor - Factory function that creates a base editor instance
* @returns Creator function for editors
*/
const createEditor: (makeEditor: () => Editor) => (
tagName: string,
attributes: { [key: string]: any },
children: any[]
) => Editor;
/**
* Create a Text object creator
* @param tagName - The tag name (typically "text")
* @param attributes - Text formatting attributes (bold, italic, etc.)
* @param children - Text content
* @returns Slate Text node
*/
function createText(
tagName: string,
attributes: { [key: string]: any },
children: any[]
): Text;Usage Example:
import { createText, createEditor } from "slate-hyperscript";
import { createEditor as makeEditor } from "slate";
// Create text node directly
const textNode = createText("text", { bold: true }, ["Hello world"]);
// Create custom editor creator
const myCreateEditor = createEditor(makeEditor);Advanced token system for programmatic selection handling and token manipulation.
/**
* Add an anchor token to the end of a text node
* @param text - Text node to add anchor token to
* @param token - Anchor token to add
*/
function addAnchorToken(text: Text, token: AnchorToken): void;
/**
* Get the offset if a text node has an associated anchor token
* @param text - Text node to check
* @returns Tuple of offset and token, or undefined if no anchor token
*/
function getAnchorOffset(text: Text): [number, AnchorToken] | undefined;
/**
* Add a focus token to the end of a text node
* @param text - Text node to add focus token to
* @param token - Focus token to add
*/
function addFocusToken(text: Text, token: FocusToken): void;
/**
* Get the offset if a text node has an associated focus token
* @param text - Text node to check
* @returns Tuple of offset and token, or undefined if no focus token
*/
function getFocusOffset(text: Text): [number, FocusToken] | undefined;Usage Example:
import { addAnchorToken, AnchorToken, createText } from "slate-hyperscript";
// Create a text node and programmatically add selection tokens
const textNode = createText("text", {}, ["Hello world"]);
const anchorToken = new AnchorToken({ offset: 5 });
addAnchorToken(textNode, anchorToken);The following JSX elements are available by default when using the jsx factory:
// Basic document structure
<editor>...</editor> // Creates Editor with content and optional selection
<element>...</element> // Creates Element nodes with children
<text>...</text> // Creates Text nodes with formatting
<fragment>...</fragment> // Creates arrays of Descendant nodes
// Selection positioning
<anchor /> // Marks selection anchor point
<focus /> // Marks selection focus point
<cursor /> // Marks collapsed selection point
<selection>...</selection> // Creates explicit Selection objectsUsage Examples:
/** @jsx jsx */
import { jsx } from "slate-hyperscript";
// Basic elements
const element = <element type="paragraph">Hello world</element>;
const textNode = <text bold italic>Formatted text</text>;
// Document fragments
const fragment = (
<fragment>
<element>First paragraph</element>
<element>Second paragraph</element>
</fragment>
);
// Selections in text
const withSelection = (
<editor>
<element>
Hello <anchor />beautiful<focus /> world
</element>
</editor>
);
// Collapsed selection (cursor)
const withCursor = (
<editor>
<element>
Hello <cursor />world
</element>
</editor>
);
// Explicit selection object
const selection = (
<selection>
<anchor path={[0, 0]} offset={5} />
<focus path={[0, 0]} offset={14} />
</selection>
);/**
* Base class for all selection tokens
*/
class Token {}
/**
* Represents selection anchor points
*/
class AnchorToken extends Token {
offset?: number;
path?: Path;
constructor(props?: {
offset?: number;
path?: Path;
});
}
/**
* Represents selection focus points
*/
class FocusToken extends Token {
offset?: number;
path?: Path;
constructor(props?: {
offset?: number;
path?: Path;
});
}Common errors you may encounter:
"No hyperscript creator found for tag: <tagName>" - occurs when using undefined JSX tag names"The <selection> hyperscript tag must have an <anchor> tag as a child with \path` and `offset` attributes defined."` - occurs when selection tags are missing required anchor/focus children with proper attributes"The <text> hyperscript tag can only contain text content as children." - occurs when <text> tags contain non-text children like elements"Slate hyperscript ranges must have both \<anchor />` and `<focus />` defined if one is defined, but you only defined `<anchor />`. For collapsed selections, use `<cursor />` instead."` - occurs when only one selection point is defined"Properties specified for a hyperscript shorthand should be an object, but for the custom element <tagName> tag you passed: [value]" - occurs when element shortcuts in createHyperscript options are not objectsTo use JSX syntax with slate-hyperscript, configure your TypeScript/Babel setup:
TypeScript (tsconfig.json):
{
"compilerOptions": {
"jsx": "react",
"jsxFactory": "jsx"
}
}Per-file pragma:
/** @jsx jsx */
import { jsx } from "slate-hyperscript";Element, Text, Range, Editor, Descendant, Path, etc.