@zuilib/text-editor
v0.0.2
Published
ZUI — A markdown editor component wrapping Lexical
Maintainers
Readme
@zuilib/text-editor
Markdown editor for ZUI built on Lexical: rich editing with shortcuts, raw markdown mode, read-only view, checklists, and fenced code highlighting.
When to use
- Notes, comments, or docs fields stored as markdown strings
- Controlled
value/onChangeintegration with forms or autosave - WYSIWYG-style editing without leaving markdown as the source of truth
Prerequisites
Peer dependencies (install in the consuming app):
| Package | Version |
|---------|---------|
| react, react-dom | ^18.0.0 \|\| ^19.0.0 |
| lexical | ^0.35.0 |
| @lexical/react | ^0.35.0 |
| @lexical/markdown | ^0.35.0 |
| @lexical/rich-text | ^0.35.0 |
| @lexical/code | ^0.35.0 |
| @lexical/list | ^0.35.0 |
| @lexical/link | ^0.35.0 |
| @zuilib/core | workspace / published — import core styles |
Installation
pnpm add @zuilib/text-editor @zuilib/core \
lexical @lexical/react @lexical/markdown @lexical/rich-text \
@lexical/code @lexical/list @lexical/linkMonorepo:
{
"dependencies": {
"@zuilib/text-editor": "workspace:*",
"@zuilib/core": "workspace:*",
"lexical": "^0.35.0",
"@lexical/react": "^0.35.0",
"@lexical/markdown": "^0.35.0",
"@lexical/rich-text": "^0.35.0",
"@lexical/code": "^0.35.0",
"@lexical/list": "^0.35.0",
"@lexical/link": "^0.35.0"
}
}Import rules
| Rule | Detail |
|------|--------|
| Named export | import { MarkdownEditor } from '@zuilib/text-editor' |
| Types | import type { MarkdownEditorProps } from '@zuilib/text-editor' |
| Styles | import '@zuilib/text-editor/styles.css' and @zuilib/core/styles.css |
| Controlled | Always pass value + onChange for persisted content |
| Mode switches | Switching edit-raw → edit-md re-mounts Lexical with latest markdown (cursor-safe) |
Exports
| Subpath | Exports |
|---------|---------|
| @zuilib/text-editor | MarkdownEditor (default re-exported as named), MarkdownEditorProps |
| @zuilib/text-editor/styles.css | Editor chrome + Lexical theme classes |
Quick start
import { useState } from 'react'
import '@zuilib/core/styles.css'
import '@zuilib/text-editor/styles.css'
import { MarkdownEditor } from '@zuilib/text-editor'
function Notes() {
const [value, setValue] = useState('# Hello\n\n- [ ] Try checklists')
return (
<MarkdownEditor
value={value}
onChange={setValue}
placeholder="Start writing…"
/>
)
}Modes
| mode | UI | onChange |
|--------|-----|------------|
| 'edit-md' (default) | Lexical rich editor + markdown shortcuts | Emits markdown string |
| 'edit-raw' | Plain <textarea> with markdown source | Emits markdown string |
| 'view' | Read-only rendered content | No editing (onChange unused) |
<MarkdownEditor mode="edit-md" value={md} onChange={setMd} />
<MarkdownEditor mode="edit-raw" value={md} onChange={setMd} />
<MarkdownEditor mode="view" value={md} />Toggle modes in parent state; the editor preserves content via an internal ref when remounting Lexical after raw editing.
Props (MarkdownEditorProps)
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| value | string | '' | Markdown source (controlled) |
| onChange | (value: string) => void | — | Called on every edit |
| mode | 'edit-md' \| 'edit-raw' \| 'view' | 'edit-md' | Editing surface |
| placeholder | string | 'Start writing...' | Empty state hint |
| readOnly | boolean | false | Disables editing in Lexical modes |
| autoFocus | boolean | false | Focus on mount |
| className | string | — | Root wrapper class |
Markdown features
Shortcuts (edit-md): headings (#), lists, blockquote, links, fenced code (via CodeBlockShortcutPlugin), checklists (- [ ] via ChecklistShortcutPlugin).
Built-in plugins: history (undo/redo), lists, checklists, links, markdown sync (MarkdownSyncPlugin), code highlighting (CodeHighlightPlugin).
Not included: file uploads, collaborative editing, or custom Lexical node registration — extend by forking or wrapping MarkdownEditor.
Form integration
With @zuilib/form:
<FormField control={form.control} name="body">
{({ field }) => (
<MarkdownEditor
value={field.value}
onChange={field.onChange}
mode="edit-md"
/>
)}
</FormField>Ensure both CSS entry points are loaded in the app layout.
Architecture notes (for extenders)
- Source:
src/MarkdownEditor.tsx, plugins undersrc/plugins/ - Lexical namespace:
ZuiTextEditor - Markdown import/export uses
@lexical/markdowntransformers (CHECK_LISTprioritized for import) edit-rawbypasses Lexical; switching back toedit-mdcaptureslatestValueRefand bumpsmountKeyto avoid cursor jumps
Related packages
@zuilib/core— design tokens and base styles@zuilib/form— react-hook-form wiring
Build (maintainers)
pnpm --filter @zuilib/text-editor build