barocss / math

Integrations: Host adapters v0.1.1 · Core ^0.4.1 · MIT. Host SDK licenses and compatibility requirements are separate from the MIT math-editor core.

TinyMCE integration (development preview)

The examples below use its public entry points. See the release guide.

Open the TinyMCE example · Host support · Validation

This independently implemented adapter uses TinyMCE 8's public plugin, selection, serialization, mode and undo APIs. It does not depend on another math editor's code.

import tinymce from "tinymce";
import katex from "katex";
import { registerBarocssMath } from "@barocss/math-editor-tinymce";
import "@barocss/math-editor/style.css";
import "@barocss/math-editor-tinymce/style.css";
import "katex/dist/katex.min.css";

registerBarocssMath(tinymce, {
  locale: "en",
  render(latex, host, displayMode) {
    // Optional renderer: treat LaTeX as untrusted input.
    katex.render(latex, host, {
      displayMode,
      throwOnError: false,
      trust: false,
    });
  },
});

await tinymce.init({
  target: document.querySelector<HTMLElement>("#editor")!,
  // Configure the TinyMCE license and locally served assets in your host.
  plugins: "barocssmath",
  toolbar: "undo redo | barocssmath",
  menu: { insert: { title: "Insert", items: "barocssmath barocssmathblock" } },
  noneditable_class: "mceNonEditable",
});

Register the plugin before tinymce.init. Options are captured per editor when it initializes. editing: "inline" is the default: an existing formula opens at its position in the text, and insertion opens at the current selection. Both inline TinyMCE hosts and classic iframe hosts support this behavior. The math field lives in the same document as the formula.

Choose editing: "panel" for the previous explicit Apply/Cancel workflow. panelHost applies only to that option and must be outside TinyMCE's editable body. Without it, the panel follows the editable element in inline TinyMCE mode or the editor container in classic iframe mode. toolbarHost can provide a separate math toolbar in either editing mode, including outside an iframe.

Styles in a classic iframe

CSS imported into the application page does not style TinyMCE's iframe. Serve the core CSS, this adapter's CSS, and any preview renderer's CSS (with their font assets) inside the iframe using TinyMCE's content_css option. For example, after copying/bundling those assets to your application's public asset directory:

await tinymce.init({
  target: document.querySelector<HTMLTextAreaElement>("#editor")!,
  plugins: "barocssmath",
  content_css: [
    "/assets/math-editor.css", // @barocss/math-editor/style.css
    "/assets/math-editor-tinymce.css", // @barocss/math-editor-tinymce/style.css
    "/assets/katex.min.css", // When using the optional KaTeX preview renderer
  ],
  // Supply your normal TinyMCE assets, toolbar and license configuration.
});

Keep the application-page CSS imports when using an outside toolbar or panel. The asset URLs above are examples; the package does not inject styles into another document automatically.

The barocssmath toolbar button edits a selected formula or starts an inline formula. Click an existing formula, or select it and press Enter, to edit it. The Insert menu offers inline and block formulas. Existing unsupported model data remains visible and cannot be replaced by an empty draft.

import type { TinyMCEMathPlugin } from "@barocss/math-editor-tinymce";

const math = editor.plugins.barocssmath as TinyMCEMathPlugin;
math.insert(String.raw`\frac{x^2}{y}`, "inline");
math.insert(String.raw`\begin{pmatrix}1&0\\0&1\end{pmatrix}`, "block");
math.edit(); // Selected formula; returns false when editing is unavailable.
math.cancel();

editor.execCommand("BarocssMath", false, { kind: "block", latex: "x=y" });
const html = editor.getContent();
editor.setContent(html);
editor.mode.set("readonly");
editor.remove();

Opening or cancelling a draft does not modify saved host content. The inline insertion marker preserves any selected prose until Apply; Cancel restores that selection. Apply replaces or inserts one atomic node inside one undoManager.transact call. Clicking outside a compact inline field commits without taking focus back. Ctrl/Cmd+Enter applies explicitly; Escape first closes suggestions and then cancels. Expanding More tools keeps the draft open until an explicit Apply/Cancel, matching the shared field's panel behavior.

Temporary controls stop input, clipboard and pointer events from reaching the host's noneditable-object handlers. TinyMCE still owns surrounding prose, selection, Backspace/Delete and document Undo/Redo. A second open command does not discard the active draft. Loading content, undo/redo, read-only mode and editor removal close it. Applying checks that its target still exists with the same source data; insertion checks that the document has not changed since the selection bookmark was captured.

The inline field opens after TinyMCE finishes its click/command focus handling. insert() / edit() returning true means opening was accepted; the input is mounted/focused on the next animation frame. The API closes pending openings on Cancel, content replacement, read-only transitions and editor removal too.

Inline formulas persist as span, block formulas as div, with these attributes:

Attribute Meaning
data-barocss-math inline or block
data-latex Portable LaTeX fallback
data-math-document Authoritative versioned math document JSON
data-math-size Display scale, 50–200 percent
contenteditable="false" Atomic host content

Normal getContent() serialization removes transient math UI from TinyMCE's detached PreProcess clone before parsing the HTML, then replaces preview descendants with escaped LaTeX in its AST filter. This prevents the inline field's block controls from being reparented out of the formula by HTML normalization. Bogus subtrees and a registered temporary attribute also keep drafts out of raw Undo snapshots. Use the normal serialization lifecycle; no_events: true bypasses the adapter's preprocessing and is not supported for saving active drafts. TinyMCE's default schema preserves data-* attributes; host sanitizers or custom schemas must also preserve the attributes above. Sanitizing or importing the surrounding HTML remains the host application's responsibility.

The local demo loads TinyMCE core, icons, theme, DOM model and skin from the pinned NPM package. It declares license_key: "gpl" only inside its unpublished Vite development entry and refuses production initialization. The reusable adapter sets no license or cloud configuration. Hosts must deliberately choose GPL or their own eligible commercial configuration before deploying TinyMCE. No premium features, embedded keys, CDN scripts or tracking are added by this adapter.

Official API references: custom plugins, UndoManager, serializer, Vite bundling, and license configuration.

Run the real-browser regression in apps/math-integrations/tests/tinymce-check.js against the local demo server. It covers Apply/Cancel, one-step undo/redo, HTML round trips, read-only mode, draft invalidation and destroy cleanup.

The public static sample shows setup guidance until the host license is explicitly configured. Local development settings do not authorize a production TinyMCE or CKEditor deployment.

Continuous editing checks

The workspace EDIT-019 run on 2026-09-10 passes both math block and math inline modes in a TinyMCE inline: true host, using Chromium on macOS. It covers nested editing, repeated formula Undo/Redo, Apply as one host history event, Save/reload/Restore, re-edit and Cancel. Inline also checks Enter commit, Right-arrow exit, prose input after the formula and Undo of that prose edit. See validation evidence.

An empty saved formula shows the localized empty-formula placeholder so it remains clickable. The preview renderer is called only when LaTeX is nonempty. The label is presentation only; saved HTML still contains empty formula content.

Classic iframe hosts, native OS IME/clipboard and other browser engines need separate validation. The continuous editing run does not certify those targets.

Barocss Math Editor core · 0.8.0 (workspace) · MIT License · Barocss adapters: MIT · Host SDK licenses are separate