API Reference

Autumn Note v3.1.0 — Fast. Lightweight. Reliable. Efficient.

Installation

Install via npm (or pnpm / yarn):

npm install autumnnote

Or use the CDN — no build step needed:

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/autumnnote/dist/autumnnote.css">
<script src="https://cdn.jsdelivr.net/npm/autumnnote"></script>
Requirements: installing from npm needs Node 22 LTS (22.22.2+) or Node 24.15+. The editor itself runs in any modern browser — the CDN build has no requirements.

Framework Wrappers v1.6.0

Official React and Vue 3 wrappers ship as separate packages in the same pnpm workspace. Each wrapper is a thin lifecycle bridge — it mounts an editor instance on the host element and exposes the Context object to the parent component via ref.

React — autumnnote-react

Install the wrapper alongside the core:

npm install autumnnote autumnnote-react
import { useRef } from 'react';
import AutumnNoteEditor from 'autumnnote-react';
import 'autumnnote/dist/autumnnote.css';

function MyEditor() {
  const editorRef = useRef(null);

  function handleSave() {
    const html = editorRef.current.getHTML();
    console.log(html);
  }

  return (
    <>
      <AutumnNoteEditor
        ref={editorRef}
        options={{
          placeholder: 'Start typing…',
          height: 300,
          bubbleToolbar: true,
          onChange: (html) => console.log(html),
        }}
      />
      <button onClick={handleSave}>Save</button>
    </>
  );
}

The component uses forwardRef + useImperativeHandle to expose the underlying Context instance. All instance methods (getHTML, setHTML, invoke, etc.) are accessible via the ref. The editor initialises once on mount; to reinitialise with new options, pass a new key prop.

Props:

PropTypeDescription
optionsAsnOptionsEditor configuration object. All AsnOptions fields are accepted.
classNamestringCSS class applied to the container <div>.
styleCSSPropertiesInline styles applied to the container <div>.
refReact.Ref<Context>Forwarded ref — exposes the Context instance.

Vue 3 — autumnnote-vue

Install the wrapper alongside the core:

npm install autumnnote autumnnote-vue
<script setup>
import { ref } from 'vue';
import AutumnNoteEditor from 'autumnnote-vue';
import 'autumnnote/dist/autumnnote.css';

const editorRef = ref(null);

function handleSave() {
  const html = editorRef.value.editor.value.getHTML();
  console.log(html);
}
</script>

<template>
  <AutumnNoteEditor
    ref="editorRef"
    :options="{ placeholder: 'Start typing…', height: 300 }"
  />
  <button @click="handleSave">Save</button>
</template>

The component uses defineExpose({ editor }) where editor is a Vue ref<Context | null>. Access the instance via editorRef.value.editor.value. The editor is created in onMounted and destroyed in onUnmounted. Use v-if to force remount on options change.

Props:

PropTypeDescription
optionsAsnOptionsEditor configuration object. All AsnOptions fields are accepted.

Quick Start

Wrap any <textarea> or <div> in your HTML:

import AutumnNote from 'autumnnote';
import 'autumnnote/dist/autumnnote.css';

const editor = AutumnNote.create('#editor', {
  placeholder: 'Start typing…',
  height: 300,
  bubbleToolbar: true,
  onChange(html) {
    console.log('content changed:', html);
  },
});

Get and set content:

editor.setHTML('<p>Hello <strong>world</strong></p>');
const html = editor.getHTML();
const markdown = editor.getMarkdown();
editor.destroy(); // clean up when done

All Options 50+ options

Pass these to AutumnNote.create(selector, options) or AutumnNote.setDefaults(options).

OptionTypeDefaultDescription
placeholderstring''Placeholder text when editor is empty.
heightnumber200Editor minimum height in px.
minHeightnumber100Minimum height of the editable area.
maxHeightnumber0Maximum height in px. 0 = unlimited.
focusbooleanfalseAuto-focus editor on initialization.
resizablebooleantrueShow drag-handle in statusbar to resize the editor.
statusbarbooleantrueShow the statusbar (word/char count, resize handle). false hides it, e.g. for a read-only viewer; getWordCount() / getCharCount() keep working.
readOnlybooleanfalseStart in read-only (non-editable) mode. Toggle at runtime with setDisabled().
spellcheckbooleantrueEnable browser spell-check.
toolbarArray<Array<…>>defaultToolbar2D array of button groups. Each item is a built-in button name ('bold'), a name from buttons / registerButton(), or a ButtonDef object.
stickyToolbarbooleanfalseStick toolbar to viewport top when page is scrolled.
stickyToolbarOffsetnumber0Top offset in px for sticky toolbar (e.g. fixed nav bar height).
toolbarOverflow'wrap' | 'scroll''wrap'Toolbar overflow strategy when buttons don't fit on one row.
bubbleToolbarbooleanfalseShow a mini floating toolbar above selected text.
bubbleToolbarItemsstring[]see belowButton names in the bubble toolbar. Default: ['bold','italic','underline','link','foreColor','hiliteColor','removeFormat'].
theme'light' | 'dark' | 'auto''light'Color theme. 'auto' follows the OS setting. Switch at runtime with editor.updateOptions({ theme: 'dark' }); colours are customisable through themeVars.
focusColorstring | nullnullCustom focus-ring colour (e.g. '#f97316').
themeVarsobject | nullnullDesign-token overrides for this editor, e.g. { primary: '#f97316', radius: '10px' }. See Theming.
zIndexOffsetnumber0Added to the z-index of every floating layer (tooltips, popovers, dialogs, fullscreen) — e.g. to sit above a host modal.
popupContainerstring | Element | ShadowRootnullWhere dialogs, tooltips and menus mount (default document.body). Use inside a focus-trapping modal or a shadow root.
direction'ltr' | 'rtl''ltr'Text direction for the editable area.
defaultFontFamilystring'Arial'Default font family applied to the editor on init.
defaultFontSizestring'14px'Default font size.
fontFamiliesstring[]10 fontsOptions shown in the font-family dropdown.
fontSizesstring[]'8px'–'72px'Sizes in the font-size dropdown.
lineHeightsstring[]'1.0'–'3.0'Values in the line-height dropdown.
paragraphStyles{ value, label }[]Normal, H1–H6, Quote, CodeBlock formats in the paragraph-style dropdown (value is a block tag).
colorSwatchesstring[][]Custom swatches prepended to the colour palette (toolbar, bubble toolbar, context menu).
colorPalettestring[] | nullnullReplaces the built-in 24-colour palette in the toolbar, bubble toolbar and context menu.
tabSizenumber4Spaces inserted per Tab key press (in code blocks).
maxCharsnumber0Max character count. 0 = unlimited. Shows warning in statusbar near limit.
maxWordsnumber0Max word count. 0 = unlimited.
historyLimitnumber100Maximum undo/redo history steps.
pasteAsPlainTextbooleanfalseForce plain-text paste — strip all HTML.
pasteCleanHTMLbooleantrueSanitise HTML on paste (removes scripts, event handlers, etc.).
pasteStripAttributesbooleanfalseStrip class, style, and data-* attributes from pasted HTML.
maxPasteSizenumber5242880Maximum paste size in bytes (default 5 MB, 0 = unlimited).
markdownPastebooleantrueConvert pasted Markdown to HTML.
markdownShortcutsbooleantrueInline Markdown triggers: **bold**, ## heading, - item, etc.
allowImageUploadbooleantrueAllow file uploads in the image dialog.
maxImageSizenumber5Maximum image upload size in MB.
linkDefaultsobject{ openInNewTab: false, … }Link dialog defaults: openInNewTab, rel (always includes noopener), defaultProtocol. Relative links are never prefixed.
videoProvidersarray | nullnullExtra video sources: [{ name, match: RegExp, embed: (match, url) => embedUrl }], tried before YouTube/Vimeo.
iframeHostsstring[] | nullnullExtra hostnames whose iframes survive sanitisation (exact hostnames, HTTPS only). List only hosts you trust.
codeHighlightbooleantrueAuto-load Prism.js for syntax highlighting in code blocks.
codeHighlightCDNstringPrism 1.29 CDNPrism CDN base URL (override to self-host).
autoSavebooleanfalseSave content to localStorage on every change.
autoSaveKeystring'autumnnote-autosave'localStorage key for auto-save.
autoSaveRestorebooleanfalseShow restore banner when a draft exists (requires autoSave: true).
autoSaveRestoreTimeoutnumber7Max draft age in days for restore. 0 = no expiry.
useBootstrapbooleanfalseApply Bootstrap button classes to toolbar buttons.
useFontAwesomebooleantrueRender toolbar icons as Font Awesome glyphs (requires FA CSS).
fontAwesomeClassstring'fas'FA prefix class ('fas' for v5, 'fa-solid' for v6).
iconsobject | nullnullPer-editor icon overrides keyed by button or icon name — SVG markup, or a CSS class list.
buttonsobject | array | nullnullPer-editor button definitions, usable by name in toolbar.
keyMapobject | nullnullKeyboard shortcut overrides merged over the defaults: false disables, a string rebinds to a command or button, a function handles it.
tableHeaderRowbooleanfalseInsert a <thead> row when creating tables.
mentionobject | nullnull@mention autocomplete config. See mention options.
langstring | object'en'UI language. Built-in: 'en' 'vi' 'ja' 'zh' 'fr' 'de' 'es' 'ko'. Pass an object to override individual strings.

Callback options

OptionSignatureDescription
onChange(html: string) => voidFires when content changes (debounced).
onFocus(ctx: Context) => voidFires when editor receives focus.
onBlur(ctx: Context) => voidFires when editor loses focus.
onInit(ctx: Context) => voidFires after all modules have initialised.
onDestroy(ctx: Context) => voidFires before the editor is destroyed.
onSelectionChange(ctx: Context) => voidFires on cursor or selection change.
onBeforeCommand({ name, value?, source }) => void | falseFires before a toolbar, shortcut, context-menu or bubble-toolbar command. Return false to cancel.
onPaste(data: {text, html}) => void | false | stringFires on every paste, before insertion. Return false to cancel, or an HTML string to insert instead (sanitised).
onImageUpload(files: File[]) => voidCustom image upload handler (replaces default inline embed).
onImageError(err) => voidFires when image upload fails.
onCharLimitReached(ctx: Context) => voidFires when maxChars is reached.
onWordLimitReached(ctx: Context) => voidFires when maxWords is reached.
onAutoSaveRestore(html, ctx) => voidFires after user restores a draft.

Static Methods

Methods on the AutumnNote object itself (not on an editor instance).

AutumnNote.create(selector, options?)

Creates one or more editor instances. Returns a single Context when selector matches one element, or an array when it matches several. Caches instances in a WeakMap — calling create on the same element twice returns the cached instance.

const editor = AutumnNote.create('#my-editor', {
  height: 350,
  bubbleToolbar: true,
});
// Multiple elements
const editors = AutumnNote.create('.editor', { height: 200 });

AutumnNote.destroy(selector)

Destroys all editor instances matching selector and restores the original element.

AutumnNote.getInstance(selector)

Returns the Context for a given element, or null if none exists.

AutumnNote.setDefaults(options)

Merges options into the global defaults — applied to every future create() call.

AutumnNote.setDefaults({
  theme: 'dark',
  bubbleToolbar: true,
  lang: 'vi',
});

AutumnNote.resetDefaults()

Restores global defaults to factory values.

AutumnNote.registerModule(name, ModuleClass)

Registers a custom module that will be included in every future editor instance. Modules receive the Context object in their constructor and must implement initialize() and optionally destroy().

AutumnNote.use(plugin, options?)

Installs a plugin globally. Plugin buttons are registered immediately (before create()); install() is called after all built-in modules initialise. See Plugin API.

AutumnNote.hasPlugin(name)

Returns true if a plugin with the given name has been registered globally.

AutumnNote.registerButton(btnDef)

Registers a single button definition in the global registry so it can be referenced by name string in toolbar config. Call ctx.invoke('toolbar.rebuild') after registering on an already-running editor.

AutumnNote.registerIcon(name, icon)

Sets the icon for a button or icon name in every editor: SVG markup, or a CSS class list such as 'bi bi-type-bold'. The per-editor icons option wins.

AutumnNote.version

String containing the library version, e.g. '3.0.0'.

Instance Methods

Methods on a Context object returned by AutumnNote.create().

Content

editor.getHTML()

Returns the current content as an HTML string.

editor.setHTML(html)

Sets the editor content. The HTML is sanitised before insertion.

editor.getText()

Returns the plain-text content (no HTML tags).

editor.setText(text)

Sets plain-text content (HTML-escaped, wraps in <p>).

editor.getMarkdown()

Converts current content to Markdown and returns the string.

editor.setMarkdown(md)

Converts Markdown to HTML and sets editor content.

editor.insertHTML(html)

Inserts HTML at the current cursor position.

editor.insertText(text)

Inserts plain text at the current cursor position.

editor.clear()

Clears all editor content.

editor.clearHistory()

Resets the undo/redo history stack.

editor.isEmpty()

Returns true when the editor has no meaningful content.

State & Info

editor.getWordCount()

Returns the current word count (CJK-aware via Intl.Segmenter).

editor.getCharCount()

Returns the current character count (excluding newlines).

editor.setDisabled(disabled)

Enables or disables the editor. true = read-only, toolbar hidden.

editor.updateOptions(options)

Merges options into a live editor. Theme, themeVars, focusColor, zIndexOffset, toolbar options, statusbar, resizable and popupContainer apply immediately; passing an unchanged value does nothing, so framework wrappers can call it on every render.

editor.downloadHTML(filename?) / .downloadText() / .downloadMarkdown()

Triggers a browser download of the content in the specified format. Default filenames: 'document.html', 'document.txt', 'document.md'.

editor.print(title?)

Opens the content in a new window and triggers the browser print dialog.

editor.invoke(path, ...args)

Invokes a method on a registered module. Format: 'moduleName.methodName'.

editor.invoke('toolbar.rebuild');       // Rebuild toolbar after button registration
editor.invoke('editor.bold');           // Apply bold
editor.invoke('findReplace.show');      // Open Find dialog
editor.invoke('fullscreen.toggle');     // Toggle fullscreen

Events

editor.on(eventName, handler)

Subscribes to an editor event. Returns an unsubscribe function.

const unsub = editor.on('change', (html) => {
  console.log('changed:', html);
});
// Later:
unsub(); // unsubscribe

editor.off(eventName, handler)

Unsubscribes a specific handler from an event.

editor.registerModule(name, ModuleClass)

Registers and initialises a custom module on this specific instance only.

Plugin

editor.use(plugin, options?)

Installs a plugin on this instance only. Plugin buttons are registered immediately; if the toolbar is already rendered, call editor.invoke('toolbar.rebuild').

editor.getPlugin<T>(name)

Returns the public API returned by plugin.install(), or null.

editor.destroy()

Removes all editor DOM, fires onDestroy, calls plugin.uninstall() on all plugins, and restores the original element.

Callbacks & Events

Events can be subscribed in two ways: as option callbacks (passed to create()) or via editor.on().

Tip: Option callbacks and on() listeners both fire for the same event. Use callbacks for one-time setup; use on() when you need to unsubscribe later.
// Option callback
const editor = AutumnNote.create('#editor', {
  onChange(html) { /* ... */ },
  onFocus(ctx)   { /* ... */ },
  onBlur(ctx)    { /* ... */ },
  onInit(ctx)    { /* editor is ready */ },
  onDestroy(ctx) { /* cleanup */ },
});

// Programmatic subscription
const unsub = editor.on('change', (html) => { /* ... */ });
editor.on('selectionChange', (ctx) => { /* cursor moved */ });
editor.on('focus', (ctx) => { /* ... */ });
editor.on('blur',  (ctx) => { /* ... */ });
editor.on('beforeCommand', ({ name, source }) => name !== 'codeview'); // false cancels
editor.on('paste', ({ text }) => text.length > 10000 ? false : undefined);

Toolbar Configuration

The toolbar option is a 2D array — each inner array is a button group (separated by a divider). Items can be built-in button names, names from the buttons option or registerButton(), or ButtonDef objects imported from the library.

import AutumnNote, {
  boldBtn, italicBtn, underlineBtn,
  ulBtn, olBtn, linkBtn, imageBtn,
  undoBtn, redoBtn,
  defaultToolbar, // full default toolbar
} from 'autumnnote';

// By name — works from JSON, framework props or the UMD build
AutumnNote.create('#editor', {
  toolbar: [['bold', 'italic', 'underline'], ['ul', 'ol'], ['link', 'image'], ['undo', 'redo']],
});

// Or with the exported definitions
const editor = AutumnNote.create('#editor', {
  toolbar: [
    [boldBtn, italicBtn, underlineBtn],
    [ulBtn, olBtn],
    [linkBtn, imageBtn],
    [undoBtn, redoBtn],
  ],
});

Or mix named button objects with string names (after registering custom buttons):

AutumnNote.registerButton({
  name: 'myButton',
  icon: 'star',          // SVG id or FontAwesome class name
  tooltip: 'My Action',
  action: (ctx) => { ctx.insertHTML('<mark>highlighted</mark>'); },
  isActive: (ctx) => false,
});

const editor = AutumnNote.create('#editor', {
  toolbar: [[boldBtn, italicBtn, 'myButton']],
});

All exported buttons

ExportTooltipType
boldBtnBold (Ctrl+B)button
italicBtnItalic (Ctrl+I)button
underlineBtnUnderline (Ctrl+U)button
strikeBtnStrikethroughbutton
inlineCodeBtnInline Code (Ctrl+`)button
superscriptBtnSuperscriptbutton
subscriptBtnSubscriptbutton
alignLeftBtn / alignCenterBtn / alignRightBtn / alignJustifyBtnAlignmentbutton
ulBtn / olBtn / checklistBtnListsbutton
indentBtn / outdentBtnIndent / Outdentbutton
undoBtn / redoBtnUndo / Redobutton
hrBtnHorizontal Rulebutton
linkBtn / imageBtn / videoBtnInsert dialogsbutton
tableBtnInsert Tablegrid
emojiBtn / iconBtnEmoji / FA Iconbutton
foreColorBtn / backColorBtnText / Highlight Colorcolorpicker
paragraphStyleBtnParagraph Styleselect
fontFamilyBtn / fontSizeBtn / lineHeightBtnTypographyselect
removeFormatBtn / directionBtnUtilitiesbutton
codeviewBtn / fullscreenBtnViewbutton
findBtn / findReplaceBtn / printBtn / shortcutsBtnToolsbutton
defaultToolbarFull default toolbar arrayarray

What's New v3.1.0

Version 3.1 replaces the browser's deprecated document.execCommand with the editor's own formatting engine. Bold, colours, fonts, links, headings, lists and indentation now produce the same markup and toolbar state on Chrome, Firefox and Safari.

Same result on every browser

Every command is a DOM transform the editor performs itself, tested on Chromium, Firefox and WebKit. Toolbar buttons read their state from the document, so they show exactly what the command toggles — including underline inside inline code, where the old API got it wrong.

Markup changes

  • Strikethrough is written as <s> (not <strike>).
  • Colour, highlight, font family and font size are <span style>, never <font>.
  • Indenting a paragraph sets margin-left: 40px instead of wrapping it in a borderless <blockquote>.
  • Existing content in the old forms is still read and edited correctly.

Copy and cut

The context-menu Copy/Cut and the copy buttons use the async Clipboard API, which browsers only provide on HTTPS and localhost. A cut never deletes text that did not reach the clipboard.

Fixes

  • Inserting an emoji or icon could overwrite text selected elsewhere on the page.
  • setMarkdown(getMarkdown()) now keeps underline, colour/font spans, superscript and subscript.
  • The character count no longer includes invisible caret anchors.

Full list in the CHANGELOG.

What's New v3.0.0

Version 3.0 is a customisation release: the look, shortcuts, icons, buttons and dropdown lists can all be changed per editor without forking or rebuilding the SCSS.

Theming with CSS custom properties

Every colour, radius and font token is a --an-* property. Theme every editor from CSS, per mode from .an-theme-dark, or one editor through themeVars — no Sass build. Themes can be switched at runtime and never touch <body>.

// Every editor, from CSS
      .an-container, .an-portal { --an-primary: #f97316; --an-radius: 10px; }

      // One editor
      const editor = AutumnNote.create('#editor', {
        theme: 'auto',
        themeVars: { primary: '#f97316', radius: '10px' },
      });
      editor.updateOptions({ theme: 'dark' });   // switch at runtime

Per-editor portal

Each editor mounts its dialogs, tooltips and menus in its own .an-portal, which carries the editor's theme. popupContainer moves it into a modal or shadow root; zIndexOffset lifts every floating layer.

Icons, buttons, dropdowns and shortcuts

Toolbars accept built-in button names, buttons defines buttons for one editor, and icons / registerIcon() swap icons. keyMap disables or rebinds shortcuts — the shortcuts dialog follows it.

AutumnNote.create('#editor', {
        toolbar: [['bold', 'italic', 'underline'], ['ul', 'ol'], ['link', 'save']],
        buttons: {
          save: { icon: '<svg viewBox="0 0 24 24">…</svg>', tooltip: 'Save', action: (ctx) => save(ctx.getHTML()) },
        },
        icons: { bold: 'bi bi-type-bold' },
        fontSizes: ['12px', '14px', '18px', '24px'],
        keyMap: {
          'Mod+F': false,                 // give Ctrl+F back to the browser
          'Mod+S': 'save',                // bind to a toolbar button
          'Mod+Shift+D': (ctx) => ctx.insertText(new Date().toLocaleDateString()),
        },
        onBeforeCommand: ({ name }) => name !== 'codeview' || user.isAdmin,
      });

Integration hooks

beforeCommand can cancel any command; paste handlers can cancel or rewrite a paste; linkDefaults, videoProviders and iframeHosts tune links and embeds. statusbar: false hides the statusbar (#119).

Upgrading from 2.x

  • Node 22 LTS (22.22.2+) or Node 24.15+ is required to install the package; Node 20 is no longer supported.
  • Floating UI now lives inside .an-portal — selectors such as body > .an-dialog-overlay need updating.
  • <body> no longer gets an-theme-dark / an-theme-auto; key page CSS on the editor container instead.
  • maxPasteSize is in bytes, as documented — use 5 * 1024 * 1024, not 5.
  • Shortcuts match Shift and Alt exactly (Ctrl+Shift+B no longer bolds). Add extra combos through keyMap.
  • onPaste return values are used: false cancels the paste, a string replaces it.

Full list in the CHANGELOG.

v1.8.0 highlights

Version 1.8.0 expands the public API with new Context methods, adds UMD button definitions, whole-word search, paste size limit, configurable image resize minimum, i18n improvements, and more.

Table Sort, CSV Export & Cell Padding

The Table Tooltip now includes three new data-management actions:

  • Sort Ascending / Descending — sort all rows by the active column; numeric values are compared as numbers, text uses locale-aware comparison; merged-cell layouts are handled correctly.
  • Export as CSV — downloads the full table as a UTF-8 (BOM) .csv file with proper quote-escaping for cells containing commas or newlines.
  • Cell Padding — open the size popover to apply a uniform padding (in px) to all selected cells.

A Toggle Header Row button also converts the first row between <thead><th> (header) and <tbody><td> (data), creating or removing the <thead> wrapper as needed.

Find & Replace — Regex Mode

A new .* toggle button in the Find & Replace panel enables JavaScript regular expression search. The compiled regex is cached across keystrokes for performance. Use cases: find all words matching a pattern, locate email addresses, replace formatted numbers, and so on. Works with case-sensitive mode; regex compilation errors are handled gracefully.

Code Block Line Numbers

The Code Tooltip now includes a Toggle Line Numbers button. When active, a CSS counter generates a numbered gutter on the left side of the code block — no JavaScript counting, no DOM changes to the content. The state syncs automatically when switching between code blocks.

Dark-Auto Theme

A new theme: 'auto' option makes the editor follow the operating system's dark-mode preference automatically:

AutumnNote.create('#editor', { theme: 'auto' });

The CSS @media (prefers-color-scheme: dark) activates the full dark palette when the OS is in dark mode; the editor stays light otherwise. theme: 'dark' and theme: 'light' continue to force a specific theme regardless of OS preference.

Undo / Redo Count API

Two new instance methods let host applications query the undo/redo stack depth:

editor.getUndoCount();  // → number of available undo steps
editor.getRedoCount();  // → number of available redo steps

Useful for disabling Undo/Redo toolbar buttons in custom UIs, or showing a step-counter badge in host applications.

Promise-Based @mention Search

The mention.onSearch callback now accepts both callback and Promise / async styles:

// Async / Promise style (new in 1.8.0)
AutumnNote.create('#editor', {
  mention: {
    onSearch: async (query) => {
      const res = await fetch(`/api/users?q=${query}`);
      return res.json();  // returns MentionItem[]
    }
  }
});

If the Promise rejects, the dropdown closes automatically. The original callback style remains fully supported.

Plugin API v1.4.1

The Plugin API lets you package editor extensions — custom modules, toolbar buttons, and event handlers — into a reusable, installable object. Plugins can be distributed as npm packages and installed in one line.

Plugin descriptor

A plugin is a plain object with the following fields:

FieldTypeRequiredDescription
namestring✓Unique plugin identifier. Used as key for getPlugin(name) and hasPlugin(name).
versionstring—Semantic version string — informational only, not validated by the runtime.
buttonsToolbarItemDef[]—Button definitions registered to the global button registry immediately when AutumnNote.use() is called — before any editor is created, so they are available by name string in toolbar config.
install(ctx, opts) → T—Called after all 27 built-in modules have initialised. Receives the Context and the options object passed to use(). The return value becomes the plugin's public API accessible via ctx.getPlugin(name).
uninstall(ctx) → void—Called when the editor instance is destroyed. Use this to release timers, remove external DOM, or disconnect external state.
const MyPlugin = {
  name: 'my-plugin',   // required
  version: '1.0.0',   // optional

  buttons: [           // registered BEFORE create() — usable by name in toolbar
    {
      name: 'highlight',
      icon: 'highlighter',          // SVG id or FontAwesome class suffix
      tooltip: 'Highlight selection',
      action:     (ctx) => ctx.invoke('editor.hiliteColor', '#fef08a'),
      isActive:   (ctx) => false,
      isDisabled: (ctx) => ctx.isEmpty(),
    },
  ],

  install(context, options) {
    // Full context API available here — all modules are ready
    context.on('change', (html) => { /* react to content changes */ });
    context.registerModule('myModule', MyModule);
    return { getLimit: () => options.limit ?? 0 }; // public API
  },

  uninstall(context) {
    // Clean up side-effects (timers, external DOM, subscriptions…)
  },
};

Inside install(context, options)

The context parameter is the full Context object. All methods documented in the Instance API section are available. The most useful inside plugins:

Event subscription

// Subscribe — returns an unsubscribe function
const unsub = context.on('change', (html) => {
  console.log('word count:', context.getWordCount());
});

// Available event names:
// 'change'          — content changed (debounced ~400 ms)
// 'focus'           — editor gained focus
// 'blur'            — editor lost focus

// Unsubscribe in uninstall() to avoid leaks
uninstall(ctx) { unsub(); }

Invoke built-in module methods

context.invoke('module.method', ...args) calls any public method on a registered module. Common paths:

PathDescription
editor.bold / italic / underline / strikethroughToggle text formatting at cursor.
editor.inlineCodeToggle inline <code> at cursor.
editor.foreColor / hiliteColorApply text / highlight colour. Pass colour string as 2nd arg: ctx.invoke('editor.foreColor', '#e11d48').
editor.insertHTMLInsert HTML at current cursor position.
editor.insertTextInsert plain text at current cursor position.
editor.getHTMLReturns current HTML string.
editor.setHTMLReplace entire content.
editor.undo / redoStep through history.
editor.focusFocus the editable area.
editor.afterCommandSnapshot undo history and trigger onChange. Call this after any direct DOM mutation.
toolbar.refreshRe-evaluate isActive / isDisabled on all toolbar buttons (debounced via rAF).
toolbar.rebuildTear down and re-render the entire toolbar. Use after post-create button registration.
linkDialog.showOpen the Insert Link dialog.
imageDialog.showOpen the Insert Image dialog.
findReplace.showOpen the Find dialog.
fullscreen.toggleToggle fullscreen mode.
codeview.toggleToggle HTML code view.

Register a custom module

A module is a class with initialize() (required) and destroy() (optional). It receives the Context in its constructor and can expose methods callable via context.invoke().

class WordBadgeModule {
  constructor(context) {
    this.context = context;
    this._el = null;
    this._unsub = null;
  }

  initialize() {
    // Build UI
    this._el = document.createElement('div');
    this._el.className = 'word-badge';
    this._el.textContent = '0 words';
    this.context.layoutInfo.container.appendChild(this._el);

    // React to content changes
    this._unsub = this.context.on('change', () => this._update());
    this._update();
    return this;
  }

  // Public method — callable via ctx.invoke('wordBadge.getCount')
  getCount() {
    return this.context.getWordCount();
  }

  _update() {
    const n = this.context.getWordCount();
    this._el.textContent = `${n} word${n !== 1 ? 's' : ''}`;
  }

  destroy() {
    this._unsub?.();
    this._el?.remove();
    this._el = null;
  }
}

// Register inside install():
install(context) {
  context.registerModule('wordBadge', WordBadgeModule);
  // Now callable anywhere:
  context.invoke('wordBadge.getCount'); // → number
}

Installation

// ── Global (applies to every future create() call) ─────────────────────────
AutumnNote.use(MyPlugin, { limit: 500 });
AutumnNote.hasPlugin('my-plugin'); // → true

const editor = AutumnNote.create('#editor', {
  toolbar: [[boldBtn, 'highlight']], // 'highlight' resolved from plugin.buttons
});

editor.getPlugin('my-plugin').getLimit(); // → 500

// ── Per-instance (this editor only) ────────────────────────────────────────
const editor2 = AutumnNote.create('#editor2');
editor2.use(MyPlugin, { limit: 200 });
editor2.invoke('toolbar.rebuild'); // surface new buttons in already-rendered toolbar

// ── Standalone button registration ─────────────────────────────────────────
AutumnNote.registerButton({
  name: 'timestamp',
  icon: 'clock',
  tooltip: 'Insert current timestamp',
  action: (ctx) => ctx.invoke('editor.insertText', new Date().toLocaleString()),
});
// Then reference by name in any toolbar config:
// toolbar: [[boldBtn, 'timestamp']]
Timing: AutumnNote.use(plugin) registers plugin.buttons immediately (synchronously) so they are available when Toolbar builds during create(). plugin.install() is called after all 27 built-in modules are ready — safe to call ctx.invoke(), ctx.registerModule(), and any content methods.

Internationalisation

Eight locales ship with the package: en, vi, ja, zh, fr, de, es, ko. With a bundler only en is included by default — register the ones you need so unused languages stay out of your bundle. The UMD/CDN build pre-registers all eight.

import AutumnNote from 'autumnnote';
import { vi } from 'autumnnote/i18n/vi';

AutumnNote.registerLocale('vi', vi);
const editor = AutumnNote.create('#editor', { lang: 'vi' });

// Override specific strings (no registration needed)
const editor2 = AutumnNote.create('#editor2', {
  lang: {
    toolbar: { bold: 'Đậm (Ctrl+B)' },
    findReplace: { noResults: 'Không tìm thấy' },
  },
});

// Switch language at runtime (re-create editor)
const html = editor.getHTML();
editor.destroy();
const editor3 = AutumnNote.create('#editor', { lang: 'ja' });
editor3.setHTML(html);

TypeScript

Autumn Note ships bundled TypeScript definitions (types/index.d.ts). No @types package needed.

import AutumnNote, {
  Context,
  AsnOptions,
  AsnPlugin,
  ButtonDef,
  ToolbarItemDef,
  AsnLocale,
} from 'autumnnote';

// Typed options
const options: AsnOptions = {
  height: 300,
  bubbleToolbar: true,
  onChange(html: string) { /* ... */ },
};

// Typed plugin
const myPlugin: AsnPlugin<{ version: string }> = {
  name: 'typed-plugin',
  install(ctx: Context, opts) {
    return { version: '1.0.0' };
  },
};

AutumnNote.use(myPlugin);
const editor = AutumnNote.create('#editor', options);

// Cast plugin API to typed interface
const api = editor.getPlugin<{ version: string }>('typed-plugin');
console.log(api?.version); // '1.0.0'