ReadyEditor ReadyEditor
docs/setup-usage.md

Setup & Usage Guide

Quick start

1. Add your editor element

<div class="my-editor">
  <p>Start typing here…</p>
</div>

2. Add the loader script

Place this script tag anywhere on the page (before or after the element):

<script
  src="https://cdn.readyeditor.io/releases/<version>/js/readyeditor.loader.min.js"
  data-api-key="YOUR_API_KEY"
  data-selector=".my-editor"
  data-load-css="1"
  data-plugins="auto"
  data-require-sri="1"
></script>

Replace <version> with the release pinned to your project (visible in the dashboard) and YOUR_API_KEY with your project API key.

The loader calls /api/v1/editor/init, loads the correct assets, and calls ReadyEditor.init() automatically. No additional JavaScript is required.


Textarea integration

The textarea bridge is a separate script (readyeditor.textarea.bridge.min.js) that is not auto-loaded by the loader. You must include it explicitly. It hides the original <textarea>, inserts an editor <div> in its place, and syncs content back on form submit.

<form>
  <textarea name="content" class="js-my-editor">
    <p>Initial content</p>
  </textarea>
  <button type="submit">Save</button>
</form>

<!-- 1. Loader — with data-auto-init="0" so we control timing -->
<script
  src="https://cdn.readyeditor.io/releases/<version>/js/readyeditor.loader.min.js"
  data-api-key="YOUR_API_KEY"
  data-load-css="1"
  data-plugins="auto"
  data-auto-init="0"
></script>

<!-- 2. Textarea bridge — must be loaded before calling attachTextareas() -->
<script src="https://cdn.readyeditor.io/releases/<version>/js/readyeditor.textarea.bridge.min.js"></script>

<!-- 3. Initialize once loader resolves, then attach to textareas -->
<script>
  window.ReadyEditorLoader.init({
    apiKey: 'YOUR_API_KEY',
    loadCss: true,
    plugins: 'auto',
  }).then(function() {
    ReadyEditor.attachTextareas({
      selector: 'textarea.js-my-editor',
      editorOptions: { apiKey: 'YOUR_API_KEY' }
    });
  });
</script>

Note: data-selector is omitted from the loader tag here because the bridge creates its own <div> elements and passes the selector to ReadyEditor.init() internally. The bridge keeps the <textarea> value in sync with editor content so standard form submissions work without any extra code.


Configuration options

Loader tag attributes

Attribute Default Description
data-api-key Your project API key (required)
data-selector .ready-editor CSS selector for editor elements
data-load-css 1 Load editor CSS automatically (0 to disable)
data-plugins auto auto (all entitled), none, or comma-separated list
data-disable-plugins Comma-separated list of plugins to suppress
data-toolbar-preset full full, basic, or minimal
data-toolbar-groups CSV allowlist of toolbar groups
data-toolbar-hide-groups CSV blocklist of toolbar groups
data-toolbar-overflow-groups CSV list of groups always pinned into the "More" dropdown
data-toolbar-overflow on Set to off to disable the overflow mechanism (toolbar wraps instead)
data-require-sri 1 Enforce SRI integrity on loaded assets
data-auto-init 1 Set to 0 to skip automatic initialization
data-init-endpoint /api/v1/editor/init Override the init endpoint URL

JS API (when data-auto-init="0")

window.ReadyEditorLoader.init({
  apiKey: 'YOUR_API_KEY',
  initEndpoint: '/api/v1/editor/init',
  selector: '.my-editor',
  plugins: 'auto',
  loadCss: true,
  requireSri: true,
});

Strict CSP (no secrets in HTML attributes)

If your CSP forbids putting secrets in HTML attributes, load the loader with data-auto-init="0" and call the JS API from your own bundle:

<script
  src="https://cdn.readyeditor.io/releases/<version>/js/readyeditor.loader.min.js"
  integrity="sha256-..."
  crossorigin="anonymous"
  data-auto-init="0"
></script>

<script src="/assets/readyeditor-init.js" defer></script>
// /assets/readyeditor-init.js
window.ReadyEditorLoader.init({
  apiKey: window.__READYEDITOR_API_KEY__,  // injected server-side
  selector: '.my-editor',
  loadCss: true,
  requireSri: true,
});

Reading and writing content

// Get HTML content
var instance = ReadyEditor.getInstance('.my-editor');
var html = instance.getContent();

// Set HTML content
instance.setContent('<p>Hello, World!</p>');

Multiple editors on one page

Pass a selector that matches multiple elements:

<div class="my-editor" id="editor-body">…</div>
<div class="my-editor" id="editor-notes">…</div>
ReadyEditor.init({
  selector: '.my-editor',
  apiKey: 'YOUR_API_KEY',
  onChange: function(instance) {
    console.log('Changed:', instance.element.id, instance.getContent());
  }
});

onChange callback

ReadyEditor.init({
  selector: '.my-editor',
  apiKey: 'YOUR_API_KEY',
  onChange: function(instance) {
    // Debounced auto-save
    clearTimeout(instance._saveTimer);
    instance._saveTimer = setTimeout(function() {
      saveToServer(instance.getContent());
    }, 500);
  }
});

Styling the editor

The loader applies these CSS classes you can target:

.readyeditor-container { border: 1px solid #ddd; border-radius: 4px; }
.readyeditor-toolbar   { background: #f8f9fa; padding: 6px; }
.readyeditor-root      { padding: 12px; min-height: 200px; }
.readyeditor-btn.readyeditor-btn-active { background: #0d6efd; color: #fff; }

Browser compatibility

ReadyEditor requires:

  • contentEditable (all modern browsers)
  • document.execCommand() (supported in all current browsers, though deprecated in the spec)
  • fetch (all modern browsers; polyfillable)
  • ES5+ JavaScript

Tested in Chrome, Firefox, Safari, and Edge.