alggtta

Build with Alggtta Editor

Install, render the editor, and save your content.

Install

Add `@alggtta/editor` to a React 18.2+ or 19 project. This guide uses version 7.0.5.

npm install @alggtta/[email protected] react react-dom @tiptap/[email protected] @tiptap/[email protected] @tiptap/[email protected] @tiptap/[email protected] @tiptap/[email protected] [email protected] [email protected] --save-exact

Keep all Tiptap peers on exactly 3.31.3, including when the host app already uses Tiptap. The command also installs the required Yjs peers (`yjs` ^13.6.31, `y-protocols` ^1.0.6).

Import `@alggtta/editor/styles.css` once, as shown below. On localhost or 127.0.0.1, pass a non-empty placeholder token; a production token is not needed. Production needs a valid browser license token issued for your domain.

React quickstart

Render `AlggttaEditor` and receive changes through `onUpdate`.

// src/Editor.tsx (Vite)
import { AlggttaEditor } from '@alggtta/editor'
import '@alggtta/editor/styles.css'

export default function Editor() {
  return (
    <AlggttaEditor
      token={import.meta.env.VITE_ALGGTTA_TOKEN ?? 'localhost-development-token'}
      content="<p>Start writing.</p>"
      placeholder="Write something…"
      locale="ko"
      onUpdate={({ json, html, text }) => {
        console.log({ json, html, text })
      }}
    />
  )
}
# .env.local — restart Vite after changing this file
VITE_ALGGTTA_TOKEN=your-browser-license-token

Type `/` to insert blocks. Select text to format it. Use `editable={false}` when the same document should be read-only.

Save and load

Persist `json` from `onUpdate` and pass it back as `content` when opening a document. Use `html` for HTML output and `text` for plain text. This example saves one draft in this browser.

import { useEffect, useRef, useState } from 'react'
import type { JSONContent } from '@tiptap/core'
import { AlggttaEditor } from '@alggtta/editor'
import '@alggtta/editor/styles.css'

const draftKey = 'editor-draft'

export default function DraftEditor() {
  const [initialContent, setInitialContent] = useState<JSONContent | null>(null)
  const [loadError, setLoadError] = useState(false)
  const saveBlocked = useRef(false)

  useEffect(() => {
    let draft: JSONContent = { type: 'doc', content: [{ type: 'paragraph' }] }
    try {
      const raw = localStorage.getItem(draftKey)
      if (raw !== null) {
        const saved = JSON.parse(raw)
        if (saved?.type !== 'doc' || !Array.isArray(saved.content)) throw new Error('Invalid draft')
        draft = saved
      }
    } catch {
      setLoadError(true)
      return // Keep the stored draft untouched.
    }
    setInitialContent(draft)
  }, [])

  if (loadError) return <p role="alert">Draft could not be loaded safely. Original kept.</p>
  if (!initialContent) return null

  return (
    <AlggttaEditor
      token={import.meta.env.VITE_ALGGTTA_TOKEN ?? 'localhost-development-token'}
      content={initialContent}
      onDocumentLoaded={({ wasEmptied, futureSchemaVersion }) => {
        saveBlocked.current = wasEmptied || futureSchemaVersion !== null
        if (saveBlocked.current) setLoadError(true)
      }}
      onUpdate={({ json }) => {
        if (saveBlocked.current) return
        try {
          localStorage.setItem(draftKey, JSON.stringify(json))
        } catch {
          console.error('Draft could not be saved.')
        }
      }}
    />
  )
}

For shared or cross-device documents, load and save through your own server API instead of localStorage. Wait for the initial document before mounting the editor; do not overwrite active edits with a background fetch.

Next.js

Put the editor in a Client Component. Use a `NEXT_PUBLIC_` variable for the browser license token.

// app/editor/editor-client.tsx
'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 ?? 'localhost-development-token'}
      content="<p>Start writing.</p>"
      onUpdate={({ json }) => console.log(json)}
    />
  )
}
// app/editor/page.tsx
import EditorClient from './editor-client'

export default function Page() {
  return <EditorClient />
}
# .env.local — restart Next.js after changing this file
NEXT_PUBLIC_ALGGTTA_TOKEN=your-browser-license-token

Apply the save/load pattern above inside this Client Component. Browser license tokens are visible to visitors; keep server API secrets out of public environment variables.

JavaScript

In a browser app with a bundler, mount the editor into an existing element. React and the peers from the installation command are still required.

<div id="editor"></div>
import { mount } from '@alggtta/editor'
import '@alggtta/editor/styles.css'

const handle = mount('#editor', {
  token: 'your-browser-license-token',
  content: '<p>Start writing.</p>',
  onUpdate: ({ json }) => console.log(json),
})

// Call when your page or view is removed:
// handle.unmount()

Use `handle.update({ editable: false })` to change options. Call `handle.unmount()` when removing the view to release the editor.