Framework Guides

CyteEditor provides dedicated adapter packages for popular frameworks. This guide covers the complete integration steps for each framework, from installation to a working editor.

Quick start (Vue 3 only): If you use Vue 3 and want everything in one package, install cyte-editor instead. It bundles the core engine, Vue 3 adapter, License SDK, and all Pro plugins. For other frameworks or fine-grained control, follow the modular setup below.

Vue 3

The official Vue 3 adapter with Composition API support and v-model:html two-way binding.

Requirements: Vue ^3.3.0

Installation

npm install @cyte-editor/core @cyte-editor/vue3

Import Styles

Import both the core styles and the adapter styles in your entry file:

import '@cyte-editor/core/style.css'
import '@cyte-editor/vue3/style.css'

Basic Usage

<template>
  <div>
    <CyteEditor
      v-model:html="content"
      placeholder="Start writing…"
      locale="en-US"
    />
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { CyteEditor } from '@cyte-editor/vue3'
import '@cyte-editor/core/style.css'
import '@cyte-editor/vue3/style.css'

const content = ref('<p>Hello, CyteEditor!</p>')
</script>

Content Binding

Vue 3 uses v-model:html for two-way binding:

<CyteEditor v-model:html="content" />

You can also use the explicit form:

<CyteEditor :html="content" @update:html="content = $event" />

Toolbar Customization

Configure which toolbar items to display via the toolbar prop:

<CyteEditor
  v-model:html="content"
  :toolbar="['bold', 'italic', 'underline', '|', 'heading', 'align']"
/>

For full control, replace the toolbar entirely using the #toolbar scoped slot:

<CyteEditor v-model:html="content">
  <template #toolbar="{ manager, activeStates, disabledStates }">
    <div class="my-toolbar">
      <button
        :class="{ active: activeStates.bold }"
        :disabled="disabledStates.bold"
        @click="manager?.getEditor().chain().focus().toggleBold().run()"
      >Bold</button>
    </div>
  </template>
</CyteEditor>

You can also extend the default toolbar with the #toolbar-prepend and #toolbar-append slots.

Vue 2

The Vue 2 adapter using Options API and :html prop with @update:html event.

Requirements: Vue ^2.7.0

Installation

npm install @cyte-editor/core @cyte-editor/vue2

Import Styles

import '@cyte-editor/core/style.css'
import '@cyte-editor/vue2/style.css'

Basic Usage

<template>
  <div>
    <CyteEditor
      :html="content"
      placeholder="Start writing…"
      locale="en-US"
      @update:html="content = $event"
    />
  </div>
</template>

<script>
import { CyteEditor } from '@cyte-editor/vue2'
import '@cyte-editor/core/style.css'
import '@cyte-editor/vue2/style.css'

export default {
  components: { CyteEditor },
  data() {
    return {
      content: '<p>Hello, CyteEditor!</p>',
    }
  },
}
</script>

Content Binding

Vue 2 does not support v-model:html. Use the :html prop with the @update:html event:

<CyteEditor :html="content" @update:html="content = $event" />

Toolbar Customization

Configure which toolbar items to display via the toolbar prop:

<CyteEditor
  :html="content"
  :toolbar="['bold', 'italic', 'underline', '|', 'heading', 'align']"
  @update:html="content = $event"
/>

For full control, replace the toolbar using the toolbar scoped slot:

<CyteEditor :html="content" @update:html="content = $event">
  <template slot="toolbar" slot-scope="{ manager, activeStates, disabledStates }">
    <div class="my-toolbar">
      <button
        :class="{ active: activeStates.bold }"
        :disabled="disabledStates.bold"
        @click="manager && manager.getEditor().chain().focus().toggleBold().run()"
      >Bold</button>
    </div>
  </template>
</CyteEditor>

React

The React adapter with hooks-based API and onChange callback.

Requirements: React ^18 || ^19

Installation

npm install @cyte-editor/core @cyte-editor/react

Import Styles

import '@cyte-editor/core/style.css'
import '@cyte-editor/react/style.css'

Basic Usage

import { useState } from 'react'
import { CyteEditor } from '@cyte-editor/react'
import '@cyte-editor/core/style.css'
import '@cyte-editor/react/style.css'

export default function MyEditor() {
  const [content, setContent] = useState('<p>Hello, CyteEditor!</p>')

  return (
    <div>
      <CyteEditor
        html={content}
        placeholder="Start writing…"
        locale="en-US"
        onChange={({ html }) => setContent(html)}
      />
    </div>
  )
}

Content Binding

React uses the html prop and onChange callback:

<CyteEditor
  html={content}
  onChange={({ html }) => setContent(html)}
/>

The onChange callback receives an object with html and json properties.

Toolbar Customization

Configure which toolbar items to display via the toolbar prop:

<CyteEditor
  html={content}
  toolbar={['bold', 'italic', 'underline', '|', 'heading', 'align']}
  onChange={({ html }) => setContent(html)}
/>

For full control, use the toolbarRender render prop:

<CyteEditor
  html={content}
  onChange={({ html }) => setContent(html)}
  toolbarRender={({ manager, activeStates, disabledStates }) => (
    <div className="my-toolbar">
      <button
        className={activeStates.bold ? 'active' : ''}
        disabled={disabledStates.bold}
        onClick={() => manager?.getEditor().chain().focus().toggleBold().run()}
      >
        Bold
      </button>
    </div>
  )}
/>

Angular

The Angular adapter with standalone component support for Angular 17+.

Requirements: Angular ^17 || ^18 || ^19

Installation

npm install @cyte-editor/core @cyte-editor/angular

Import Styles

Add the styles to your global styles or component:

/* styles.css or angular.json styles array */
@import '@cyte-editor/core/style.css';
@import '@cyte-editor/angular/style.css';

Register Components

// app.module.ts
import { NgModule } from '@angular/core'
import { CyteEditorComponent } from '@cyte-editor/angular'

@NgModule({
  imports: [CyteEditorComponent],
  // ...
})
export class AppModule {}

Basic Usage

<!-- app.component.html -->
<cyte-editor
  [html]="content"
  [placeholder]="'Start writing…'"
  [locale]="'en-US'"
  (onChange)="onContentChange($event)"
></cyte-editor>
// app.component.ts
import { Component } from '@angular/core'

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
})
export class AppComponent {
  content = '<p>Hello, CyteEditor!</p>'

  onContentChange(event: { html: string }) {
    this.content = event.html
  }
}

Content Binding

Angular uses property binding [html] and event binding (onChange):

<cyte-editor [html]="content" (onChange)="content = $event.html"></cyte-editor>

Toolbar Customization

Configure which toolbar items to display via the toolbar input:

<cyte-editor
  [html]="content"
  [toolbar]="['bold', 'italic', 'underline', '|', 'heading', 'align']"
  (onChange)="content = $event.html"
></cyte-editor>

For full control, provide a custom template via toolbarTemplate:

<cyte-editor
  [html]="content"
  [toolbarTemplate]="myToolbar"
  (onChange)="content = $event.html"
></cyte-editor>

<ng-template #myToolbar let-props>
  <div class="my-toolbar">
    <button
      [class.active]="props.activeStates['bold']"
      [disabled]="props.disabledStates['bold']"
      (click)="props.manager?.getEditor().chain().focus().toggleBold().run()"
    >Bold</button>
  </div>
</ng-template>

Svelte

The Svelte adapter compatible with both Svelte 4 and Svelte 5.

Requirements: Svelte ^4 || ^5

Installation

npm install @cyte-editor/core @cyte-editor/svelte

Import Styles

import '@cyte-editor/core/style.css'
import '@cyte-editor/svelte/style.css'

Basic Usage

<script>
  import { CyteEditor } from '@cyte-editor/svelte'
  import '@cyte-editor/core/style.css'
  import '@cyte-editor/svelte/style.css'

  let content = '<p>Hello, CyteEditor!</p>'
</script>

<CyteEditor
  html={content}
  placeholder="Start writing…"
  locale="en-US"
  onChange={(e) => content = e.html}
/>

Content Binding

Svelte uses the html prop and onChange event:

<CyteEditor
  html={content}
  onChange={(e) => content = e.html}
/>

Toolbar Customization

Configure which toolbar items to display via the toolbar prop:

<CyteEditor
  html={content}
  toolbar={['bold', 'italic', 'underline', '|', 'heading', 'align']}
  onChange={(e) => content = e.html}
/>

For full control, use the toolbarRender callback with click delegation:

<script>
  let editorManager = null

  function handleToolbarClick(e) {
    const btn = e.target.closest('[data-cmd]')
    if (!btn || !editorManager) return
    const chain = editorManager.getEditor().chain().focus()
    const commands = {
      toggleBold: () => chain.toggleBold().run(),
      toggleItalic: () => chain.toggleItalic().run(),
    }
    commands[btn.dataset.cmd]?.()
  }
</script>

<!-- svelte-ignore a11y_click_events_have_key_events -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div onclick={handleToolbarClick}>
  <CyteEditor
    html={content}
    onChange={(e) => content = e.html}
    onReady={(mgr) => editorManager = mgr}
    toolbarRender={({ activeStates, disabledStates }) => `
      <div class="my-toolbar">
        <button class="${activeStates.bold ? 'active' : ''}"
                ${disabledStates.bold ? 'disabled' : ''}
                data-cmd="toggleBold">
          Bold
        </button>
      </div>
    `}
  />
</div>

Vanilla JS

Direct integration using EditorManager — no framework required.

Requirements: None (framework-free, supports IIFE/UMD)

Installation

npm install @cyte-editor/core @cyte-editor/vanilla

Import Styles

import '@cyte-editor/core/style.css'

Basic Usage

import { EditorManager } from '@cyte-editor/core'
import '@cyte-editor/core/style.css'
import { renderToolbar } from '@cyte-editor/vanilla'

const el = document.querySelector('#editor')
const manager = EditorManager.create(el, {
  height: '400px',
  locale: 'en-US',
})

manager.setContent('<p>Hello, CyteEditor!</p>')

const toolbar = renderToolbar(document.querySelector('#toolbar'), {
  isProMode: false,
})
toolbar.attachEditor(manager.getEditor(), manager)

Content API

Vanilla JS uses the EditorManager API directly:

// Set content
manager.setContent('<p>New content</p>')

// Get content
const html = manager.getHTML()
const json = manager.getJSON()
const text = manager.getText()

// Listen for changes
manager.on('update', ({ html }) => {
  console.log('Content changed:', html)
})

Framework Comparison

FrameworkPackageComponentContent Binding
Vue 3@cyte-editor/vue3<CyteEditor>v-model:html
Vue 2@cyte-editor/vue2<CyteEditor>:html + @update:html
React@cyte-editor/react<CyteEditor>html + onChange
Angular@cyte-editor/angular<cyte-editor>[html] + (onChange)
Svelte@cyte-editor/svelte<CyteEditor>html + onChange
Vanilla@cyte-editor/vanillaEditorManagersetContent() / getHTML()

Pro Plugins (Optional)

Pro plugins extend CyteEditor with advanced capabilities. Each plugin is a separate package:

npm install @cyte-editor/pro-export
npm install @cyte-editor/pro-paste
npm install @cyte-editor/pro-revision
  • pro-export — Import/export Markdown, Word (.docx), and HTML.
  • pro-paste — Smart clipboard handling for Word, Excel, WPS, and HTML.
  • pro-revision — Version snapshots, rich-text diff, and side-by-side comparison.

Pro plugins require @cyte-editor/license and a valid license key:

npm install @cyte-editor/license

Registering Plugins

Plugins can be registered at creation time or dynamically:

// At creation
const manager = EditorManager.create(el, {
  plugins: [ProPaste(), ProExport(), ProRevision()],
  license: { key: 'your-license-key' },
})

// Dynamically
manager.use(ProPaste())

For framework adapters, pass plugins through the same plugins config option. See the API Reference for full configuration details.

TypeScript Support

CyteEditor is written in TypeScript and ships complete type definitions out of the box. No additional @types packages are required.

Next Steps