AI-native React editor built on Lexical.
The current entry point exports a modern Lexical editor designed for AI chat and agent workflows: rich prompt input, structured context, attachments, tool intent, and serializable AI parts.
- React 18 + Lexical 0.44
- Vite library build with ESM, CJS, CSS, and TypeScript declarations
- Rich text controls for bold, italic, underline, strike, inline code, headings, quote, code block, ordered list, unordered list, and links
- Markdown shortcuts and undo/redo history
- Product-configurable AI tool modes and model selector
- Slash menu, @ mention suggestions, attachment upload adapter, and prompt history
- shadcn-inspired AI Elements preset with people/files/folders/actions defaults
- Registry-driven AI Elements gallery, system stats and implementation workflow
- Product-level agent console surface with composer, task plan, sources, file context, terminal output, test results and payload inspection
- AI Elements primitives for mention picker, attachments, models, tool modes, file upload, file dropzone, image insert, prompt history, sources, citations, reasoning, task plans, file trees, terminal output, test results, and payload inspection
- Structured AI chips inside the Lexical document tree:
- context
- attachment
- tool
- Structured AI blocks inside the Lexical document tree:
- artifact
- tool call with status, actions, logs, output, run id, and invocation id
- image
- Selected block toolbar for delete, duplicate, move up/down, and copy JSON
- Image toolbar for alignment, width presets, caption, and alt text
- Update commands for tool-call lifecycle and image layout
- Imperative React ref API for agent/runtime integration
- Submit payload with user text, Lexical JSON, portable schema v2, structured parts, context, attachments, active tool mode, and model
npm installnpm run startOpen the local Vite URL and try the demo editor.
npm run buildBuild output:
dist/react-tapable-editor.mjsdist/react-tapable-editor.cjsdist/react-tapable-editor.cssdist/index.d.ts
import LexicalTapableEditor from 'react-tapable-editor';
import 'react-tapable-editor/style.css';
export function Composer() {
return (
<LexicalTapableEditor
context={[{ id: 'repo', label: 'react-tapable-editor', type: 'repo' }]}
attachments={[{ id: 'brief', name: 'editor-brief.md' }]}
models={[{ id: 'fast', label: 'Fast model' }]}
promptHistory={['Summarize the latest artifact.']}
onAIBlockAction={event => {
console.log(event.action, event.id);
}}
onSubmit={payload => {
console.log(payload.text);
console.log(payload.parts);
console.log(payload.portable);
}}
/>
);
}Use AIElementsComposer when you want a designed composer surface instead of a
bare editor core. It ships with a shadcn-inspired container, default mention
suggestions for people/files/folders/actions, model options, tool modes, and
prompt history.
import {
AIElementsAgentConsole,
AIElementsCatalog,
AIElementsComposer,
AIElementsGallery,
AIElementsStats,
AIElementsSystemMap,
AIElementsWorkflow,
MentionPicker,
PayloadInspector,
SourcesBlock,
TaskPlanBlock,
aiElementsMentionSuggestions,
} from 'react-tapable-editor';
import 'react-tapable-editor/style.css';
export function WorkspaceComposer() {
return (
<>
<AIElementsStats />
<AIElementsGallery />
<AIElementsSystemMap />
<AIElementsCatalog />
<AIElementsWorkflow />
<MentionPicker items={aiElementsMentionSuggestions} />
<SourcesBlock
sources={[
{ id: 'docs', title: 'Design notes', url: '/docs/ai-elements' },
]}
/>
<TaskPlanBlock
tasks={[
{ id: '1', title: 'Review context', status: 'done' },
{ id: '2', title: 'Run implementation agent', status: 'doing' },
]}
/>
<AIElementsComposer
title="Agent workspace"
context={[{ id: 'repo', label: 'react-tapable-editor', type: 'repo' }]}
onSubmit={payload => runAgent(payload)}
/>
<AIElementsAgentConsole
context={[{ id: 'repo', label: 'react-tapable-editor', type: 'repo' }]}
onSubmit={payload => runCodingAgent(payload)}
/>
<PayloadInspector payload={null} />
</>
);
}The preset is intentionally opinionated but not closed: pass
mentionSuggestions, models, toolModes, promptHistory, and the normal
editor callbacks to replace any default.
The primitives can also be used without the composer. They are ordinary React components that share the same TypeScript types as the editor payload, so a product can place them in sidebars, popovers, agent consoles, or artifact workspaces while keeping one schema contract.
import {
INSERT_AI_BLOCK_COMMAND,
INSERT_AI_CHIP_COMMAND,
INSERT_IMAGE_COMMAND,
UPDATE_AI_BLOCK_COMMAND,
UPDATE_IMAGE_COMMAND,
} from 'react-tapable-editor';The command payload types are exported as TypeScript types.
import {
createLexicalJSONFromPortableDocument,
exportPortableDocumentToMarkdown,
exportPortableDocumentToPlainText,
migratePortableDocument,
} from 'react-tapable-editor';The portable document is a versioned schema that can be stored or sent to an AI runtime without coupling the caller to Lexical internals.
import { useRef } from 'react';
import LexicalTapableEditor, {
LexicalTapableEditorHandle,
} from 'react-tapable-editor';
export function AgentComposer() {
const editorRef = useRef<LexicalTapableEditorHandle | null>(null);
return (
<LexicalTapableEditor
ref={editorRef}
onSubmit={() => {
editorRef.current?.insertAIBlock({
id: 'run-1',
kind: 'tool-call',
title: 'Agent run',
status: 'running',
});
}}
/>
);
}Planning and architecture notes live in codebase-wiki/.
npm run docs:wiki:devThe public documentation site lives in docs/. It is separate from the
internal codebase wiki and is organized around Philosophy, Components, Blocks,
Runtime, Recipes, and API.
npm run docs:devnpm run release:checkThis runs the production build, Playwright e2e suite, and wiki build.