@alggtta/editor
v6.8.1
Published
Alggtta Editor with Tiptap 3.x and DaisyUI 5
Maintainers
Readme
@alggtta/editor
React/TypeScript Notion-style editor built on Tiptap 3, Tailwind CSS v4, and DaisyUI 5.
@alggtta/editor (core-first since v3) keeps the default package focused on the core editor. Heavy features such as database blocks, Mermaid, AI, and export helpers are available through opt-in subpath imports.
Install
npm install @alggtta/editor --save-exactInstall peer dependencies in your app:
npm install react react-dom @tiptap/[email protected] @tiptap/[email protected] @tiptap/[email protected] @tiptap/[email protected] @tiptap/[email protected] [email protected] [email protected] --save-exactKeep all Tiptap singleton peers on exactly 3.31.3. Tiptap packages require
matching patch versions. This patch fixes
GHSA-cp6q-959q-f8rh;
3.28.x–3.29.x also have a known React NodeView caret regression.
@tiptap/y-tiptap uses its
independent 3.0.9 release line. [email protected] and [email protected] are also
required singleton peers because the main entry eagerly links the collaboration
extension graph.
Yarn Classic 1.x consumers must use the same exact peers with --ignore-optional:
yarn add --ignore-optional --exact @alggtta/editor react react-dom @tiptap/[email protected] @tiptap/[email protected] @tiptap/[email protected] @tiptap/[email protected] @tiptap/[email protected] [email protected] [email protected]That flag skips every optional dependency in this Yarn install. Its important
effect in this graph is preventing the redundant newer menu copies resolved
from @tiptap/react's optional ranges; the two exact root menu packages above
keep menu functionality available. Explicitly install any other optional
package your app needs. This workaround is specific to Yarn Classic 1.x, not a
general Yarn Modern requirement.
TypeScript
Minimum TypeScript: >=5.3
typescript is declared as an optional peer dependency — JavaScript consumers need
nothing. TypeScript consumers need 5.3 or newer because the CommonJS declarations served
to exports["*"].require.types (dist/**/*.d.cts) annotate their type-only edges to
ESM-only packages (yjs, @tanstack/react-table) with
with { "resolution-mode": "import" }. TypeScript only parses that attribute from 5.3
onward; on 5.2 and older it is a syntax error (TS1005) that skipLibCheck: true
does not suppress, so the CJS type surface fails to load entirely.
Measured: 5.2.2 → TS1005 (tsc exit 2, with or without skipLibCheck); 5.3.2 → clean.
The ESM declarations (dist/**/*.d.ts) carry no such attribute and work on older
compilers — the floor applies only to the require condition.
Production usage requires an Alggtta token. Localhost development still works with a token-shaped value such as tok_dev.
Basic Usage
import { AlggttaEditor } from '@alggtta/editor'
import '@alggtta/editor/styles.css'
export function EditorPage() {
return (
<AlggttaEditor
token={process.env.NEXT_PUBLIC_ALGGTTA_TOKEN ?? ''}
content="<h1>Hello</h1><p>Type / for commands.</p>"
onUpdate={({ editor, json, html, text }) => {
console.log({ json, html, text })
}}
/>
)
}Next.js App Router
Use the editor from a client component.
'use client'
import { AlggttaEditor } from '@alggtta/editor'
import '@alggtta/editor/styles.css'
export default function EditorClient() {
return (
<AlggttaEditor
token={process.env.NEXT_PUBLIC_ALGGTTA_TOKEN ?? ''}
variant="document"
onUpdate={({ json }) => {
void fetch('/api/document', {
method: 'POST',
body: JSON.stringify(json),
})
}}
/>
)
}Vite / CRA / React
import { AlggttaEditor } from '@alggtta/editor'
import '@alggtta/editor/styles.css'
export function App() {
return (
<AlggttaEditor
token={import.meta.env.VITE_ALGGTTA_TOKEN}
placeholder="Write something..."
/>
)
}Visual Variants
Use variant to fit the editor into different layouts:
<AlggttaEditor token={token} variant="document" />
<AlggttaEditor token={token} variant="embedded" />
<AlggttaEditor token={token} variant="bare" />document: default document canvas with comfortable padding.embedded: compact shell for dashboards and admin panels.bare: minimal wrapper when your app owns the layout.
License UI
token is required. verifyEndpoint defaults to https://cdn.alggtta.com.
<AlggttaEditor
token={token}
licenseFallback={({ error }) => (
<div role="alert">Editor license check failed: {error}</div>
)}
/>Subpath Imports
import { useAlggttaEditor, useAutosave } from '@alggtta/editor/headless'
import { definePlugin, resolvePlugins, PluginSlot } from '@alggtta/editor/plugin'
import { createSchedulePlugin, ScheduleEditor } from '@alggtta/editor/schedule'
import { createGuideFlowPlugin } from '@alggtta/editor/guideflow'
import { createMathPlugin } from '@alggtta/editor/math'
import { createDatabaseExtensions, databaseSlashCommands } from '@alggtta/editor/database'
import { createMermaidExtensions, mermaidSlashCommands } from '@alggtta/editor/mermaid'
import { createAIExtensions, getDocumentContext } from '@alggtta/editor/ai'
import { markdownToHtml, htmlToMarkdown } from '@alggtta/editor/export'
import { LicensedGate, useLicenseVerification } from '@alggtta/editor/license'
import { useComments, CommentSidebar } from '@alggtta/editor/comments'
import { createCollaborationExtensions, usePresence } from '@alggtta/editor/collab'
import { UniversalEditor } from '@alggtta/editor/legacy'The main entry includes the core blocks: paragraph, headings 1-3, lists, task list, quote, divider, link, highlight, image, table, code block, slash menu, bubble menu, and drag handle. Pass preset="full" to also mount the advanced blocks (callout, toggle, columns, embed, file attachment, mention, wiki link, comments, find/replace, synced block) and their slash commands. Math (KaTeX) is excluded from full to keep the bundle lean — it's a heavy optional peer; add createMathPlugin() from @alggtta/editor/math via extensionConfig.plugins (or MathExtension/InlineMathExtension from @alggtta/editor/legacy via extensionConfig.customExtensions) if you need it.
For math on Node 20, use npm install --save-exact [email protected]. KaTeX 0.18.5 adds a CLI dependency requiring Node 22.12+, so an engine-strict Node 20 install of that version fails. The editor retains the compatible ^0.18.4 peer range; workspace/demo testing uses 0.18.5 on Node 22.
The main entry also exports the framework-agnostic mount(el, props) factory, the <alggtta-editor> Web Component (defineAlggttaEditorElement()), and the getWikiLinks(doc) link-enumeration API. To keep the core lean, the heavier page-chrome components (VersionHistory, PageMeta, TableOfContents) live in @alggtta/editor/legacy, and the version/migration utilities (createPageVersionFromAITransaction, MigrationRegistry) in @alggtta/editor/headless.
Embed anywhere (no React app)
The mount(el, props) factory and <alggtta-editor> Web Component work from any
stack. The bundle served from cdn.alggtta.com keeps React external, so load the
react / react-dom UMD globals first, then the editor. Every CDN asset is
token-gated, so pass ?token= on both the script and the stylesheet — a
<link> / <script> tag can't send an Authorization header (no token → 401;
invalid, expired, or wrong-domain token → 403):
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<link rel="stylesheet" href="https://cdn.alggtta.com/editor.css?token=YOUR_TOKEN" />
<script src="https://cdn.alggtta.com/editor.umd.js?token=YOUR_TOKEN"></script>
<alggtta-editor token="YOUR_TOKEN" preset="full"></alggtta-editor>
<!-- or imperatively: window.AlggttaEditor.mount('#el', { token, preset: 'full' }) -->From npm you can call
mount/defineAlggttaEditorElementdirectly (React resolved as a peer) — no UMD globals needed.
Building a wiki? The editor ships the primitives (
[[/@triggers,getWikiLinks, autosave). Durable storage — backlinks, full-text search, and versions — is handled by the private companion package@alggtta/wiki-store, provided to licensees on request (contact https://alggtta.com).
Optional entries may require their matching peer dependencies, for example @tanstack/react-table@^9.1.2 for database blocks and mermaid for Mermaid diagrams. The database subpath uses TanStack Table v9's feature-explicit API and is not compatible with v8. Export/import UI loads html2pdf.js and mammoth only when the PDF or DOCX actions are used.
Optional Feature Composition
import { AlggttaEditor } from '@alggtta/editor'
import { createDatabaseExtensions, databaseSlashCommands } from '@alggtta/editor/database'
<AlggttaEditor
token={token}
extensionConfig={{
customExtensions: createDatabaseExtensions(),
customSlashCommands: databaseSlashCommands,
}}
/>Export UI is also opt-in. Import the dropdown from /export and inject it into the editor footer:
import { AlggttaEditor } from '@alggtta/editor'
import { ExportDropdown, exportSlashCommands } from '@alggtta/editor/export'
<AlggttaEditor
token={token}
extensionConfig={{
customSlashCommands: exportSlashCommands,
}}
renderFooterControls={({ editor, allowedFeatures }) =>
allowedFeatures.includes('*') || allowedFeatures.includes('export')
? <ExportDropdown editor={editor} />
: null
}
/>Only expose optional commands for features you actually register or render.
Plugin Development
Use the lightweight /plugin entry to bundle custom Tiptap extensions and
slash commands into a mount-time plugin. Plugin command ids and extension names
must be unique; command ids also cannot collide with ids declared by the host's
customSlashCommands.
import { AlggttaEditor } from '@alggtta/editor'
import { ClockIcon } from '@heroicons/react/24/outline'
import { Extension, definePlugin } from '@alggtta/editor/plugin'
import '@alggtta/editor/styles.css'
const timestampPlugin = definePlugin({
id: 'com.example.timestamp',
version: '1.0.0',
extensions: [Extension.create({ name: 'exampleTimestampBehavior' })],
slashCommands: [
{
id: 'com.example.timestamp.insert',
title: 'Insert timestamp',
description: 'Insert the current time',
icon: ClockIcon,
command: (editor) => {
editor.chain().focus().insertContent(new Date().toISOString()).run()
},
},
],
})
export function PluginEditor() {
return (
<AlggttaEditor
token={import.meta.env.VITE_ALGGTTA_TOKEN}
extensionConfig={{ plugins: [timestampPlugin] }}
/>
)
}The plugin set is fixed when the editor is created; remount to change the
schema. External plugin packages must keep React and all Tiptap/ProseMirror
packages as peers/externals, must not import @tiptap/starter-kit at runtime,
and must publish their CSS separately. Install trusted plugins only: they run
with the host page's full JavaScript permissions. Declarative Web Component
attributes and the hosted CDN/UMD build do not load arbitrary plugin packages.
See the public Plugin Development guide for a minimal plugin definition and registration example, browser-side static rendering, document compatibility, packaging, and security guidance.
Embed Frame Security
With preset="full", the embed block shows YouTube, Figma, CodePen and X/Twitter content
in sandboxed iframes. Frame URLs are rebuilt from recognised provider links on fixed frame
hosts, but that covers only the URL a frame starts on, and YouTube and Figma frames get
allow-same-origin next to allow-scripts. Before you let embeds load, the host
application must:
- serve the editor page with
Cross-Origin-Opener-Policy: same-origin; - send
Content-Security-Policy: frame-ancestors 'none'(orX-Frame-Options: DENY) on every response that can carry user content; - never serve user-supplied HTML or SVG inline from the editor page's origin;
- list the frame hosts it wants in CSP
frame-src(https://www.youtube.com,https://www.figma.com,https://codepen.io,https://twitframe.com);default-src 'self'alone blocks every embed.
YouTube frames carry referrerpolicy="strict-origin-when-cross-origin", because YouTube
refuses to play without a Referer; this overrides a page Referrer-Policy: no-referrer
for those frames, so www.youtube.com learns the page origin (not its path or query).
Because of allow-same-origin, the frames' allow list (accelerometer, autoplay,
clipboard-write, encrypted-media, gyroscope, picture-in-picture) now takes effect for
YouTube and Figma; cap it with your own Permissions-Policy header if needed (a feature
whose allowlist omits a provider's origin, such as gyroscope=(), is not delegated to it).
A framed document can navigate itself, or open a popup that inherits its sandbox, to any
URL; the first three requirements keep such a page on your origin from reaching the editor
page.
Tailwind and DaisyUI
The package ships compiled CSS at @alggtta/editor/styles.css. DaisyUI is internally prefixed with ue- to reduce conflicts with consuming apps. You can use the editor in apps with or without Tailwind/DaisyUI.
Migration from v2
onUpdate
// v2
<UniversalEditor onUpdate={(editor) => save(editor.getJSON())} />
// v3
<AlggttaEditor onUpdate={({ json }) => save(json)} />UniversalEditor
AlggttaEditor is the recommended component (since v3). The previous UniversalEditor remains available from the legacy entry during migration:
import { UniversalEditor } from '@alggtta/editor/legacy'Optional Features
Database, Mermaid, AI, export helpers, GuideFlow blocks, and schedule blocks are no longer part of the default core entry. Import the matching subpath and pass its extensions/commands explicitly.
License
Proprietary — Copyright © 2026 Alggtta. All rights reserved. Use is governed by the Alggtta Commercial License Agreement (EULA) and a valid, domain-bound license token issued by Alggtta. See LICENSE.
Versions up to and including 5.1.1 were published under the MIT License and those already-distributed copies remain MIT; this proprietary license applies to 6.0.0 and later.
Independent feature plugins
Install only the features you need through extensionConfig.plugins:
createSchedulePlugin from @alggtta/editor/schedule, createGuideFlowPlugin from
@alggtta/editor/guideflow, createMathPlugin from @alggtta/editor/math, and the
createDatabasePlugin, createAIPlugin, createMermaidPlugin, createCommentsPlugin
factories in their existing subpaths. Use the core preset when composing all of them.
Schedule retains the existing guideflow license entitlement. createGuideFlowPlugin()
installs the map, hotel, contact, divider and staff blocks, so together with
createSchedulePlugin() it registers exactly the nodes of the legacy guideFlowExtensions
bundle: moving from customExtensions: guideFlowExtensions needs no schema or storage
migration. Install both when opening existing GuideFlow documents. Legacy exports are unchanged.
Plugins can supply React ui.toolbar, ui.sidebar, ui.footer and ui.overlay
components, mounted and licensed with their extensions. Each contribution renders inside
its own error boundary: a component that throws, or a React.lazy chunk that fails to
load, is hidden and logged without unmounting the editor. Overlays render inside the
themed editor root, and without UI contributions AlggttaEditor adds no slot wrapper or
layout element around the editor surface and body.
Headless hosts can use PluginSlot and useAlggttaEditor().plugins. See
Plugin Development for migration and UI examples.
