Editor
Rich text editor built on TipTap with a one-row toolbar, slash commands, emoji, panels and task lists, storing plain HTML.
Preview
Type / for blocks or : for emoji. Your fingers never leave the keyboard, and your coffee stays safe.
Usage
import { z } from 'zod'
import { AutoForm } from '@vitnode/core/components/form/auto-form'
import { AutoFormEditor } from '@vitnode/core/components/form/fields/editor'
const formSchema = z.object({
content: z.string().min(1, 'Write something first'),
})<AutoForm
formSchema={formSchema}
fields={[
{
id: 'content',
component: (props) => <AutoFormEditor {...props} label="Announcement" />,
},
]}
/>Toolbar
One row, even in a narrow form. Everyday tools sit up front, the rest in menus:
- Text style: paragraph or heading 1–4.
- Bold, italic and …: underline, strikethrough, inline code, alignment, Clear formatting.
- Text color, lists (bulleted, numbered, task), link, emoji, table, code block.
- + Insert: quote, code block, table, divider, emoji, audio and panels.
Slash commands
Type /, keep typing to filter (/tab finds Table), pick with the
arrow keys and Enter. Search matches translated names and English
keywords, so /table works in every language.
Emoji
Type : and a few letters (:rocket) to get suggestions, or use the
toolbar picker. Add your own emoji for every editor in vitnode.config.ts:
export const vitNodeConfig = buildConfig({
editor: {
emojis: [
{
label: 'VitNode',
emojis: [
{ name: 'vitnode', src: '/logo.svg', tags: ['logo', 'brand'] },
],
},
],
},
})name is the shortcode (:vitnode:), tags are extra search words, and
label heads the section in the picker.
Panels
Callouts in four kinds: info, warning, error, success. One paragraph is
a muted note. Add a second and the first becomes the title.
Insert one from + Insert or /panel. Picking the same kind again removes
it; another kind switches the color. Panels are saved as plain HTML,
<div class="tiptap-panel" data-panel="info">, so EditorContent renders them
as is.
Task lists
Each item stores its checkbox state, so acceptance criteria stay ticked after
saving. Start one from the toolbar, /task, or type [ ] at the start of a
line.
Keyboard shortcuts
| Action | Shortcut |
|---|---|
| Submit the form | Ctrl/⌘ + Enter |
| Bold / italic | Ctrl/⌘ + B / I |
| Underline | Ctrl/⌘ + U |
| Bulleted list | Ctrl/⌘ + Shift + 8 |
| Numbered list | Ctrl/⌘ + Shift + 7 |
| Task list | Ctrl/⌘ + Shift + 9 |
| Undo / redo | Ctrl/⌘ + Z / Shift + Z |
Ctrl/⌘ + Enter submits the surrounding form, like its submit button. Outside a form it does nothing.
Accessibility
- The toolbar is one tab stop. ← → move between buttons, Home / End jump to the ends.
- In AutoForm, the writing area is named by the label, described by the description and error, and outlined red when invalid.
- The
/and:menus announce the highlighted option, and open upward when there's no room below. - A same-size placeholder holds the spot while the editor loads, so the page doesn't jump.
Multi-language
Add multiLang to edit the content in every enabled language. A language select
(shown with two or more languages) switches the language being edited, not the
app locale.
import { multiLangValueSchema } from '@vitnode/core/lib/helpers/multi-lang'
const formSchema = z.object({
content: multiLangValueSchema({ minLength: 1 }).min(1),
})<AutoFormEditor {...props} label="Content" multiLang />The value becomes { languageCode, value }[], matching core_languages_words:
const value = [
{ languageCode: 'en', value: '<p>Hello</p>' },
{ languageCode: 'pl', value: '<p>Cześć</p>' },
]Save it with saveLanguageWords. See
Auto Form - Multi-language fields.
Rendering content
EditorContent renders stored HTML read-only, for public pages. It sanitizes
the HTML first, so a sneaky <script> never runs.
import { EditorContent } from '@vitnode/core/components/ui/editor-content'
;<EditorContent content={post.content} />Props
Prop
Type