Features
You can enable, disable, or customize each feature through the features option.
Feature Overview
Vizel enables most features by default. Set any feature to false to disable it.
| Feature | Description |
|---|---|
slashCommand | Slash command menu (type / to open) |
table | Table editing support |
tableOfContents | Auto-collected heading navigation block |
image | Image upload and resize |
codeBlock | Code blocks with syntax highlighting |
dragHandle | Per-item drag handle for reordering blocks and list items |
characterCount | Character and word counting |
textColor | Text color and highlight |
taskList | Checkbox task lists |
link | Link editing |
markdown | Markdown import/export |
mathematics | LaTeX math equations |
embed | URL embeds (YouTube, etc.) |
details | Collapsible content blocks |
callout | Info, warning, danger, tip, and note admonition blocks |
diagram | Mermaid/GraphViz diagrams |
superscript | Superscript text formatting |
subscript | Subscript text formatting |
typography | Smart quotes, em dashes, and other typographic transformations |
wikiLink | Wiki-style internal links ([[page-name]]) — opt-in |
mention | @user autocomplete — opt-in |
comment | Text annotations and comments — opt-in |
collaboration | Real-time collaboration mode (disables History) — opt-in |
Markdown Flavor Selection
Vizel supports multiple Markdown output flavors to match the platform you are targeting. The flavor option controls how content is serialized when exporting Markdown; input parsing is always tolerant and accepts all formats regardless of the selected flavor.
Available Flavors
| Flavor | Callout Output | WikiLink Output | Target Platforms |
|---|---|---|---|
"commonmark" | Blockquote fallback | Standard link [text](wiki://page) | Stack Overflow, Reddit, email |
"gfm" (default) | GitHub Alerts > [!NOTE] | Standard link [text](wiki://page) | GitHub, GitLab, DEV.to |
"obsidian" | Obsidian Callouts > [!note] | [[page]] / [[page|text]] | Obsidian, Logseq, Foam |
"docusaurus" | Directives :::note | Standard link [text](wiki://page) | Docusaurus, VitePress, Zenn, Qiita |
Usage
const editor = useVizelEditor({
flavor: 'obsidian', // Default: 'gfm'
});Extension-Specific Behavior
- Callout: Serializes admonition blocks in the format matching the selected flavor. All four callout formats are parsed regardless of flavor.
- WikiLink: When
flavoris"obsidian", wiki links serialize as[[page]]syntax. For all other flavors, they serialize as standard Markdown links[text](wiki://page). - Mention: Always serializes as
@usernameregardless of flavor.
TIP
You can override the flavor-driven defaults for individual extensions. For example, set wikiLink.serializeAsWikiLink or callout.markdownFormat explicitly to override the flavor configuration.
Feature Categories
VizelFeatureOptions groups every opt-in into three categories:
| Category | Consumer question | Examples |
|---|---|---|
content | What can the document contain? | image, table, mathematics, diagram, embed, details, callout, textColor, highlight, taskList, wikiLink, tableOfContents |
interaction | How does the user edit? | slashMenu, dragHandle, mention, characterCount, typography, placeholder, historyDepth |
collaboration | Who edits together? | comments, provider, versionHistory, presence |
A leaf accepts true (enable with defaults), false (disable), or an options object.
const editor = useVizelEditor({
features: {
interaction: {
slashMenu: false, // Disable slash commands
dragHandle: false, // Disable drag handle
},
content: {
table: false, // Disable tables
},
},
});TIP
Code blocks, links, Markdown import/export, find / replace, multi-block selection, and block clipboard are part of the always-on core and are not gated by VizelFeatureOptions. Configure Markdown via the top-level markdown option (e.g. markdown: { flavor: vizelGfmFlavor }).
Slash Commands
Type / to open the command menu for block insertion.
Options
| Property | Type | Description |
|---|---|---|
commands | readonly VizelCommand[] | Commands surfaced in the slash menu. Defaults to the slash-surfaced subset of vizelDefaultCommands. |
suggestion | Partial<SuggestionOptions<VizelCommand>> | Framework-specific suggestion renderer options. |
Custom Commands
The slash menu consumes the unified VizelCommand type. Each command defines one action across every surface; surfaces.slashMenu opts it into the menu. The label and description fields are locale thunks, so a single command localizes without duplication.
import type { VizelCommand } from '@vizel/core';
const customCommands: VizelCommand[] = [
{
id: 'custom/custom-block',
label: () => 'Custom Block',
description: () => 'Insert a custom block',
icon: 'lucide:box',
keywords: ['custom', 'block'],
group: 'custom',
canRun: (editor) => editor.isEditable,
run: (editor) =>
editor
.chain()
.focus()
.insertContent({
type: 'paragraph',
content: [{ type: 'text', text: 'Custom content' }],
})
.run(),
surfaces: { slashMenu: {} },
},
];
const editor = useVizelEditor({
features: {
interaction: {
slashMenu: {
commands: customCommands, // Override the slash-surfaced commands
},
},
},
});Default Commands
| Group | Commands |
|---|---|
| Text | Heading 1, Heading 2, Heading 3 |
| Lists | Bullet List, Numbered List, Task List |
| Blocks | Quote, Divider, Details, Code Block, Table |
| Media | Image, Upload Image, Embed |
| Advanced | Math Equation, Inline Math, Mermaid Diagram, GraphViz Diagram |
Images
The image feature supports drag and drop, paste, and resize.
Options
| Property | Type | Default | Description |
|---|---|---|---|
resize | boolean | true | Enable image resizing |
onUpload | (file: File) => Promise<string> | Base64 | Upload handler |
maxFileSize | number | - | Max file size in bytes |
allowedTypes | string[] | See below | Allowed MIME types |
onValidationError | (error) => void | - | Validation error callback |
onUploadError | (error, file) => void | - | Upload error callback |
Default Allowed Types
['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml']Example: Custom Upload
const editor = useVizelEditor({
features: {
content: {
image: {
onUpload: async (file) => {
const formData = new FormData();
formData.append('image', file);
const res = await fetch('/api/upload', {
method: 'POST',
body: formData,
});
const { url } = await res.json();
return url;
},
maxFileSize: 5 * 1024 * 1024, // 5MB
allowedTypes: ['image/jpeg', 'image/png', 'image/webp'],
onValidationError: (error) => {
if (error.type === 'file_too_large') {
alert('File is too large. Maximum size is 5MB.');
} else if (error.type === 'invalid_type') {
alert('Invalid file type. Only JPEG, PNG, and WebP are allowed.');
}
},
onUploadError: (error, file) => {
console.error(`Failed to upload ${file.name}:`, error);
alert('Upload failed. Please try again.');
},
},
},
},
});Code Blocks
Code blocks with syntax highlighting are part of the always-on core. Use the language picker in the slash menu or the bubble menu's node selector to choose a language. Lowlight ships every language by default — pass a custom Lowlight instance via the extensions array only if you need to restrict the available grammars.
Character Count
This feature tracks character and word counts.
Options
| Property | Type | Default | Description |
|---|---|---|---|
limit | number | null | null | Max characters (null = unlimited) |
mode | "textSize" | "nodeSize" | "textSize" | Counting mode |
wordCounter | (text: string) => number | - | Custom word counter |
Example: Character Limit
const editor = useVizelEditor({
features: {
interaction: {
characterCount: {
limit: 10000, // Max 10,000 characters
mode: 'textSize',
},
},
},
});
// Access counts
const chars = editor.storage.characterCount.characters();
const words = editor.storage.characterCount.words();
const limit = editor.storage.characterCount.limit;
const percentage = (chars / limit) * 100;Text Color & Highlight
This feature adds text color and background highlight support.
Options
| Property | Type | Description |
|---|---|---|
textColors | VizelColorDefinition[] | Custom text color palette |
highlightColors | VizelColorDefinition[] | Custom highlight color palette |
multicolor | boolean | Enable multicolor highlights |
Custom Color Palette
import type { VizelColorDefinition } from '@vizel/core';
const customColors: VizelColorDefinition[] = [
{ name: 'Brand', color: '#6366f1' },
{ name: 'Success', color: '#22c55e' },
{ name: 'Warning', color: '#f59e0b' },
{ name: 'Error', color: '#ef4444' },
];
const editor = useVizelEditor({
features: {
content: {
textColor: {
textColors: customColors,
},
highlight: {
highlightColors: customColors.map(c => ({
...c,
color: `${c.color}40`, // Add transparency
})),
},
},
},
});Markdown
Markdown import/export is part of the always-on core. The serializer flavor is selected via the top-level markdown option, not via features.
Options
| Property | Type | Default | Description |
|---|---|---|---|
flavor | VizelMarkdownFlavor | vizelGfmFlavor | Output flavor (commonmark / GFM / Obsidian / Docusaurus / Pandoc) |
encoding | VizelMarkdownEncodingOptions | {} | Per-node encoding mode ("default" or "metadata-comment") for nodes without a canonical Markdown form (embed, mention, wikiLink) |
Example
import { useVizelEditor, vizelObsidianFlavor } from '@vizel/react';
const editor = useVizelEditor({
markdown: {
flavor: vizelObsidianFlavor,
encoding: {
mention: 'metadata-comment',
},
},
});
// Export to Markdown
const md = editor.getMarkdown();
// Import from Markdown
editor.commands.setContent('# Hello\n\nWorld');Mathematics
This feature renders LaTeX math equations with KaTeX.
Options
| Property | Type | Default | Description |
|---|---|---|---|
katexOptions | KatexOptions | {} | KaTeX rendering options |
inlineInputRules | boolean | true | Enable $...$ input rules |
blockInputRules | boolean | true | Enable $$...$$ input rules |
Example
const editor = useVizelEditor({
features: {
content: {
mathematics: {
katexOptions: {
throwOnError: false,
strict: false,
},
inlineInputRules: true,
blockInputRules: true,
},
},
},
});Usage
- Inline math: Type
$E=mc^2$and press space - Block math: Type
$$on a new line, enter equation, type$$
Embeds
This feature embeds content from URLs (YouTube, Vimeo, Twitter).
Options
| Property | Type | Default | Description |
|---|---|---|---|
fetchEmbedData | Function | Built-in | Custom fetch function |
providers | VizelEmbedProvider[] | Default providers | Custom/additional providers |
pasteHandler | boolean | true | Auto-embed pasted URLs |
inline | boolean | false | Inline vs block embeds |
Default Providers
- YouTube
- Vimeo
- Twitter/X
- CodePen
- CodeSandbox
- Figma
- Loom
- Spotify
Example: Custom Provider
import type { VizelEmbedProvider } from '@vizel/core';
const customProvider: VizelEmbedProvider = {
name: 'MyService',
patterns: [/^https?:\/\/myservice\.com\/embed\/(\w+)/],
transform: (url) => `https://myservice.com/embed/${url.split('/').pop()}`,
};
const editor = useVizelEditor({
features: {
content: {
embed: {
providers: [customProvider],
pasteHandler: true,
},
},
},
});Details
This feature provides collapsible content blocks (accordion/disclosure).
Options
| Property | Type | Description |
|---|---|---|
details | object | Details container options |
detailsContent | object | Content area options |
detailsSummary | object | Summary/header options |
Example
const editor = useVizelEditor({
features: {
content: {
details: true, // Enable with defaults
},
},
});Usage
Use the slash command /details or /toggle to insert a collapsible block.
Diagrams
This feature supports Mermaid and GraphViz diagrams.
Options
| Property | Type | Default | Description |
|---|---|---|---|
mermaidConfig | MermaidConfig | {} | Mermaid configuration |
graphvizEngine | string | "dot" | GraphViz layout engine |
defaultType | "mermaid" | "graphviz" | "mermaid" | Default diagram type |
defaultCode | string | - | Default Mermaid code |
defaultGraphvizCode | string | - | Default GraphViz code |
GraphViz Engines
dot- Hierarchical (default)neato- Spring modelfdp- Force-directedsfdp- Scalable force-directedtwopi- Radialcirco- Circular
Example
const editor = useVizelEditor({
features: {
content: {
diagram: {
mermaidConfig: {
theme: 'neutral',
securityLevel: 'loose',
},
defaultType: 'mermaid',
defaultCode: `graph TD
A[Start] --> B[End]`,
},
},
},
});Links
Link editing and auto-linking are part of the always-on core. The defaults follow industry conventions (HTTPS protocol, autolink on paste, click opens in a new tab). Pass a custom @tiptap/extension-link configuration through the extensions array if you need to override the defaults.
Task Lists
This feature adds checkbox task lists with nested indentation support.
Options
| Property | Type | Description |
|---|---|---|
taskList | TaskListOptions | Task list container options |
taskItem | TaskItemOptions | Task item options |
Keyboard Shortcuts
| Shortcut | Action |
|---|---|
Tab | Indent (nest) the current task item |
Shift+Tab | Outdent (un-nest) the current task item |
Alt+↑ | Move the current task item up |
Alt+↓ | Move the current task item down |
These shortcuts also work for bullet lists and ordered lists.
Example
const editor = useVizelEditor({
features: {
content: {
taskList: {
taskItem: {
nested: true, // Allow nested task lists
},
},
},
},
});Drag Handle
This feature provides a handle for drag-and-drop block reordering. It also adds keyboard shortcuts for moving blocks and list items.
Every block gets its own handle — including individual list items (bullet, ordered, and task lists) at any nesting depth. Dragging a nested item moves only that item and preserves its descendants; numbering in ordered lists updates automatically, and task item checkbox state is preserved.
Options
| Property | Type | Default | Description |
|---|---|---|---|
enabled | boolean | true | Show drag handle |
Keyboard Shortcuts
| Shortcut | Action |
|---|---|
Alt+↑ | Move the current block or list item up |
Alt+↓ | Move the current block or list item down |
Tab | Indent (nest) a list item |
Shift+Tab | Outdent (un-nest) a list item |
The drag handle is automatically positioned next to the hovered block. For list items, the handle is shifted outside the list marker so it does not overlap the bullet or number, and its size is reduced to be less intrusive.
Example
const editor = useVizelEditor({
features: {
interaction: {
dragHandle: {
enabled: true,
},
},
},
});Block Menu
Clicking the drag handle opens a context menu for the block. The menu provides:
- Delete — Remove the block
- Duplicate — Copy the block below
- Copy / Cut — Clipboard operations
- Turn into — Convert the block to a different type (heading, list, blockquote, etc.)
The block menu is automatically included in the Vizel all-in-one component. When using the composition pattern (VizelEditor + VizelBubbleMenu), add VizelBlockMenu explicitly:
// React
import { VizelBlockMenu } from '@vizel/react';
<VizelBlockMenu />
// Vue
import { VizelBlockMenu } from '@vizel/vue';
<VizelBlockMenu />
// Svelte
import { VizelBlockMenu } from '@vizel/svelte';
<VizelBlockMenu />Wiki Links
This feature adds wiki-style [[page-name]] links for linking between pages. It supports display text aliases with [[page-name|display text]] syntax.
Options
| Property | Type | Default | Description |
|---|---|---|---|
resolveLink | (pageName: string) => string | (p) => '#' + p | Resolves a page name to a URL |
pageExists | (pageName: string) => boolean | () => true | Checks if a page exists |
getPageSuggestions | (query: string) => VizelWikiLinkSuggestion[] | - | Autocomplete suggestions |
onLinkClick | (pageName: string, event: MouseEvent) => void | - | Click callback |
Example
const editor = useVizelEditor({
features: {
content: {
wikiLink: {
resolveLink: (page) => `/wiki/${encodeURIComponent(page)}`,
pageExists: (page) => knownPages.has(page),
},
},
},
});See the Wiki Links Guide for detailed usage.
Comments
This feature adds text annotation marks for reviewing and discussion.
Example
const editor = useVizelEditor({
features: {
collaboration: {
provider: true, // comments require a provider
comments: true,
},
},
});WARNING
comments requires provider. Setting comments: true without a provider throws VizelError("INVALID_CONFIG") at editor creation.
Comment management (storage, replies, resolution) uses the framework-specific hooks/composables/runes. See Collaboration: Comments for details.
Collaboration
This feature enables real-time multi-user editing built on Yjs. When you enable it, Vizel disables the built-in History extension (Yjs handles undo/redo).
WARNING
This opt-in feature requires additional dependencies: yjs, a Yjs provider, @tiptap/extension-collaboration, and @tiptap/extension-collaboration-cursor.
Example
const editor = useVizelEditor({
features: {
collaboration: {
provider: true, // Disables built-in History; Yjs handles undo/redo
},
},
extensions: [
Collaboration.configure({ document: ydoc }),
CollaborationCursor.configure({ provider, user }),
],
});See the Collaboration Guide for setup instructions.
Internationalization (i18n)
Vizel provides full internationalization support. All UI strings (toolbar labels, slash menu items, block menu actions, find & replace, etc.) can be translated by passing a VizelLocale object.
Quick Start
Pass a locale prop to the Vizel component or the editor hook/composable/rune:
import { Vizel } from '@vizel/react';
import type { VizelLocale } from '@vizel/core';
import { createVizelLocale } from '@vizel/core';
// Create a partial locale (only override what you need)
const jaLocale = createVizelLocale({
toolbar: {
undo: '元に戻す',
redo: 'やり直す',
bold: '太字',
italic: '斜体',
},
slashMenu: {
noResults: '結果なし',
groups: { text: 'テキスト', lists: 'リスト', blocks: 'ブロック' },
},
});
<Vizel locale={jaLocale} /><script setup lang="ts">
import { Vizel } from '@vizel/vue';
import { createVizelLocale } from '@vizel/core';
const jaLocale = createVizelLocale({
toolbar: { undo: '元に戻す', redo: 'やり直す' },
});
</script>
<template>
<Vizel :locale="jaLocale" />
</template><script lang="ts">
import { Vizel } from '@vizel/svelte';
import { createVizelLocale } from '@vizel/core';
const jaLocale = createVizelLocale({
toolbar: { undo: '元に戻す', redo: 'やり直す' },
});
</script>
<Vizel locale={jaLocale} />Full Locale Override
For a complete translation, provide a full VizelLocale object:
import type { VizelLocale } from '@vizel/core';
const myLocale: VizelLocale = {
toolbar: { ariaLabel: 'Formatting', undo: 'Undo', redo: 'Redo', /* ... all fields required */ },
nodeTypes: { text: 'Text', heading1: 'Heading 1', /* ... */ },
blockMenu: { label: 'Block menu', delete: 'Delete', /* ... */ },
slashMenu: { noResults: 'No results', groups: { /* ... */ }, items: { /* ... */ } },
findReplace: { label: 'Find and replace', findPlaceholder: 'Find...', /* ... */ },
codeBlock: { languagePlaceholder: 'Language', copyCode: 'Copy', copied: 'Copied!' },
dragHandle: { ariaLabel: 'Drag to reorder block' },
saveIndicator: { saved: 'Saved', saving: 'Saving...', unsaved: 'Unsaved', error: 'Error saving' },
nodeSelector: { changeBlockType: 'Change block type', blockTypes: 'Block types', currentBlockType: 'Current block type: {type}' },
relativeTime: { justNow: 'just now', secondsAgo: '{n}s ago', minutesAgo: '{n}m ago', hoursAgo: '{n}h ago', daysAgo: '{n}d ago' },
bubbleMenu: { ariaLabel: 'Text formatting', superscript: 'Superscript', subscript: 'Subscript' },
colorPicker: { textColor: 'Text Color', highlight: 'Highlight', textColorPalette: 'Text color palette', highlightPalette: 'Highlight color palette', recent: 'Recent', hexPlaceholder: '#000000', apply: 'Apply', applyAriaLabel: 'Apply custom color' },
linkEditor: { urlPlaceholder: 'Enter URL...', apply: 'Apply', applyAriaLabel: 'Apply link', removeLink: 'Remove link', removeLinkAriaLabel: 'Remove link', openInNewTab: 'Open in new tab', visit: 'Visit', visitTitle: 'Open URL in new tab', embedAsRichContent: 'Embed as rich content' },
};Partial Locale with createVizelLocale()
Use createVizelLocale() to merge partial translations with the English defaults:
import { createVizelLocale } from '@vizel/core';
// Only override the fields you need — English defaults fill the rest
const locale = createVizelLocale({
toolbar: {
bold: 'Fett',
italic: 'Kursiv',
},
slashMenu: {
noResults: 'Keine Ergebnisse',
},
});Composition Pattern
When using the decomposed component pattern, pass locale to the editor hook and to components that display UI strings:
import { VizelEditor, VizelBubbleMenu, VizelToolbar, VizelBlockMenu, useVizelEditor } from '@vizel/react';
const editor = useVizelEditor({ locale: myLocale });
<VizelToolbar editor={editor} locale={myLocale} />
<VizelEditor editor={editor} />
<VizelBubbleMenu editor={editor} locale={myLocale} />
<VizelBlockMenu locale={myLocale} /><VizelToolbar :editor="editor" :locale="myLocale" />
<VizelEditor :editor="editor" />
<VizelBubbleMenu :editor="editor" :locale="myLocale" />
<VizelBlockMenu :locale="myLocale" /><VizelToolbar {editor} locale={myLocale} />
<VizelEditor {editor} />
<VizelBubbleMenu {editor} locale={myLocale} />
<VizelBlockMenu locale={myLocale} />Default Locale
The English locale is available as vizelEnLocale:
import { vizelEnLocale } from '@vizel/core';
console.log(vizelEnLocale.toolbar.bold); // "Bold"Toolbar Extensibility
The toolbar supports custom actions, dropdown menus, and responsive overflow for narrow viewports.
Custom Toolbar Actions
Pass an actions array to VizelToolbarDefault to customize the toolbar:
import { VizelToolbar, VizelToolbarDefault } from '@vizel/react';
import type { VizelToolbarActionItem } from '@vizel/core';
import { vizelDefaultToolbarActions } from '@vizel/core';
const myActions: VizelToolbarActionItem[] = [
...vizelDefaultToolbarActions,
{
id: 'myAction',
label: 'My Action',
icon: 'bold',
group: 'custom',
isActive: () => false,
isEnabled: () => true,
run: (editor) => { /* custom logic */ },
},
];
<VizelToolbar>
<VizelToolbarDefault editor={editor} actions={myActions} />
</VizelToolbar><script setup lang="ts">
import { VizelToolbar, VizelToolbarDefault } from '@vizel/vue';
import type { VizelToolbarActionItem } from '@vizel/core';
import { vizelDefaultToolbarActions } from '@vizel/core';
const myActions: VizelToolbarActionItem[] = [
...vizelDefaultToolbarActions,
{
id: 'myAction',
label: 'My Action',
icon: 'bold',
group: 'custom',
isActive: () => false,
isEnabled: () => true,
run: (editor) => { /* custom logic */ },
},
];
</script><script lang="ts">
import { VizelToolbar, VizelToolbarDefault } from '@vizel/svelte';
import type { VizelToolbarActionItem } from '@vizel/core';
import { vizelDefaultToolbarActions } from '@vizel/core';
const myActions: VizelToolbarActionItem[] = [
...vizelDefaultToolbarActions,
{
id: 'myAction',
label: 'My Action',
icon: 'bold',
group: 'custom',
isActive: () => false,
isEnabled: () => true,
run: (editor) => { /* custom logic */ },
},
];
</script>Dropdown Menus
Group related actions into dropdown menus using VizelToolbarDropdownAction:
import type { VizelToolbarDropdownAction } from '@vizel/core';
const headingDropdown: VizelToolbarDropdownAction = {
id: 'headings',
label: 'Headings',
icon: 'heading1',
group: 'heading',
type: 'dropdown',
options: [
{
id: 'heading1',
label: 'Heading 1',
icon: 'heading1',
group: 'heading',
isActive: (editor) => editor.isActive('heading', { level: 1 }),
isEnabled: (editor) => editor.can().toggleHeading({ level: 1 }),
run: (editor) => editor.chain().focus().toggleHeading({ level: 1 }).run(),
shortcut: 'Mod+Alt+1',
},
// ... more heading options
],
getActiveOption: (editor) =>
// Return the currently active heading option to show in the trigger
options.find((opt) => opt.isActive(editor)),
};Overflow Menu
Use VizelToolbarOverflow to show hidden actions in a popover when the toolbar is narrow:
import { VizelToolbar, VizelToolbarOverflow } from '@vizel/react';
<VizelToolbar>
{/* Main toolbar buttons */}
<VizelToolbarOverflow editor={editor} actions={overflowActions} />
</VizelToolbar><VizelToolbar>
<!-- Main toolbar buttons -->
<VizelToolbarOverflow :editor="editor" :actions="overflowActions" />
</VizelToolbar><VizelToolbar>
<!-- Main toolbar buttons -->
<VizelToolbarOverflow {editor} actions={overflowActions} />
</VizelToolbar>Next Steps
- Editor - Editor options, lifecycle, and auto-save
- Blocks - Block selection, clipboard, drag handle, and block menu
- Markdown - Flavor system, encoding modes, and round-trip
- Collaboration - Real-time editing, comments, and version history
- Theming - Customize the appearance
- Wiki Links - Wiki-style internal links
- Plugins - Extend Vizel with plugins
- API Reference