RangeMenu

RangeMenu documentation

Everything on this page applies to RangeMenu 1.x with Froala Editor v4 or v5. The package ships TypeScript source, ESM and CJS builds with type definitions, and a script-tag build.

Installation

With a bundler

Install the package file from your purchase, then register the plugin against the FroalaEditor constructor your app uses:

import FroalaEditor from 'froala-editor';
import { registerRangeMenu } from 'rangemenu';

registerRangeMenu(FroalaEditor);

new FroalaEditor('#editor'); // right-click menu is on by default

If your bundler resolves froala-editor to a single copy, one import does both steps:

import 'rangemenu/auto';

Script tag

Load RangeMenu after Froala. It registers itself against window.FroalaEditor and also exposes a small window.RangeMenu helper object.

<script src="froala/js/froala_editor.min.js"></script>
<script src="rangemenu/dist/rangemenu.min.js"></script>

Styles

The menu injects its stylesheet automatically into whichever root the editor lives in, including shadow DOM. If you prefer a stylesheet you control, link dist/rangemenu.css; it is identical to the injected text, so loading both is harmless.

Registration

registerRangeMenu(FroalaEditor) adds the plugin to FroalaEditor.PLUGINS, turns the menu on by default, and appends rangeMenu to the default pluginsEnabled list. Calling it twice is safe.

One caveat: if you pass your own pluginsEnabled array to an editor, Froala uses it verbatim. Include 'rangeMenu' in it or the plugin will not initialise for that editor.

Options

Configuration lives under the rangeMenu editor option. Three shapes are accepted:

  • rangeMenu: true (the default): the standard menu of cut, copy, paste, insert link, insert image, insert table, and select all, plus contextual sections.
  • rangeMenu: false: no RangeMenu for this editor; the browser's native menu returns.
  • rangeMenu: { ... }: full configuration.
KeyTypeDefaultWhat it does
itemsarraystandard set The menu, top to bottom. See Menu items.
contextualbooleantrue Prepend table, image, and link sections when you right-click those elements. See Contextual sections.
themestring'auto' 'light', 'dark', or 'auto' (follows the operating system, like native menus).
zIndexnumber2147483000 Stacking level of the menu.
onShowfunction Called with the editor when the menu opens.
onHidefunction Called with the editor when the menu closes.

Menu items

Each entry in items is one of three things:

A string

Strings resolve in this order:

  1. A built-in item: 'cut', 'copy', 'paste', or 'selectAll'. These come with platform-aware shortcut hints.
  2. A named item you registered with registerRangeMenuItem.
  3. Any registered Froala command: 'bold', 'insertLink', 'formatUL', 'insertTable', and so on. The command runs through Froala's own pipeline, so its title, translation, focus handling, and undo behaviour all match the toolbar. Commands whose plugin is not loaded are dropped from the menu instead of rendering dead entries.

'-', '|', 'divider', and 'separator' all draw a divider. Doubled-up or dangling dividers left behind by hidden items are collapsed automatically.

An item object

Custom items are plain objects. The full field list is in the item reference below.

{
  title: 'Insert Timestamp',
  shortcut: '⌘T',                 // display-only hint
  action: (editor) => editor.html.insert(new Date().toLocaleString()),
}

A submenu

Give an item an items array and it opens a submenu instead of running an action. Submenus nest to any depth, open on hover with intent detection or with ArrowRight, and flip to the other side when they would leave the viewport.

{
  title: 'Insert Greeting',
  items: [
    { title: 'Formal', action: (ed) => ed.html.insert('Dear colleague,') },
    { title: 'Casual', action: (ed) => ed.html.insert('Hey!') },
    {
      title: 'Multilingual',
      items: [
        { title: 'Bonjour', action: (ed) => ed.html.insert('Bonjour!') },
        { title: 'Hallo', action: (ed) => ed.html.insert('Hallo!') },
      ],
    },
  ],
}

Item reference

FieldTypeWhat it does
titlestring Display text. Required. Translated through the editor's language pack unless translate: false.
actionfunction Runs on activation, receiving (editor, item).
commandstring Name of a registered Froala command to run instead of action. The item is dropped if the command is not available on this editor.
itemsarray Submenu entries. When present, action and command are ignored.
iconstring Inline SVG markup shown before the title.
shortcutstring Right-aligned hint text such as '⌘K'. Display only; RangeMenu does not bind the key.
disabledboolean or function Greys the item out. Functions receive the editor and are evaluated every time the menu opens.
hiddenboolean or function Removes the item entirely. Same evaluation rules as disabled.
undoboolean Defaults to true: the action is wrapped in undo snapshots so it is a single Ctrl+Z step. Set false for actions that do not change content, or that manage undo themselves.
translateboolean Defaults to true. Set false to show title exactly as written.

Named items

Register an item once and refer to it by name in any editor's configuration. Useful when several editors share custom items.

import { registerRangeMenuItem } from 'rangemenu';

registerRangeMenuItem('stamp', {
  title: 'Insert Timestamp',
  action: (editor) => editor.html.insert(new Date().toLocaleString()),
});

// later, on any editor:
new FroalaEditor('#editor', {
  rangeMenu: { items: ['stamp', '-', 'cut', 'copy', 'paste'] },
});

In the script-tag build the same function is available as RangeMenu.registerItem.

Contextual sections

With contextual: true (the default), RangeMenu prepends sections based on what you right-clicked. Each section only appears when the matching Froala plugin is loaded on that editor.

Right-click targetNeeds pluginItems
Inside a table celltable Table submenu: insert row above/below, insert column before/after, delete row, delete column, delete table.
An imageimage Image submenu: remove image.
A linklink Link submenu: edit link, remove link.

Set contextual: false to show only your own items, whatever was clicked.

Theming

The menu is styled with CSS custom properties on the .rgm root, so a restyle is a few lines of CSS with no build step:

.rgm {
  --rgm-bg: #ffffff;        /* menu background */
  --rgm-text: #1d2129;      /* item text */
  --rgm-muted: #8a919c;     /* shortcuts, carets, disabled items */
  --rgm-hover: #eef1f4;     /* active item background */
  --rgm-line: #e4e7eb;      /* border and separators */
  --rgm-shadow: 0 10px 38px rgba(15, 20, 30, 0.16);
  --rgm-radius: 8px;
  --rgm-font: system-ui, sans-serif;
  --rgm-font-size: 13.5px;
}

Dark values live under .rgm[data-rgm-theme="dark"]. With theme: 'auto' the menu follows the operating system's light or dark preference, the way native menus do.

Behaviour

  • Caret placement. Right-clicking moves the caret to the pointer, so inserts land where the user clicked. A right-click inside an existing selection keeps that selection, so Cut and Copy act on it.
  • Keyboard. ArrowUp and ArrowDown move through items and skip disabled ones, ArrowRight opens a submenu, ArrowLeft closes it, Home and End jump, Enter activates, Escape closes. Focus stays in the editor the whole time, so the user's selection survives the menu.
  • Dismissal. The menu closes on outside click, Escape, scroll, resize, or when another editor's menu opens. Only one menu is open per page.
  • Paste. The built-in paste item uses the asynchronous Clipboard API, preferring HTML and falling back to plain text. Where the browser refuses clipboard access the item is a no-op and a console warning explains why.
  • Editors. Framed (default) and inline editors are both supported, as is shadow DOM. Each editor has its own configuration. A disabled editor shows the browser's native menu.

Recipes

A font submenu

Any Froala API is available inside an action, so a font picker is a mapping over your font list:

const FONTS = {
  'Georgia,serif': 'Georgia',
  '"Courier New",monospace': 'Courier New',
  'Verdana,sans-serif': 'Verdana',
};

new FroalaEditor('#editor', {
  rangeMenu: {
    items: [
      {
        title: 'Font',
        items: Object.entries(FONTS).map(([family, label]) => ({
          title: label,
          translate: false,
          action: (editor) => editor.format.applyStyle('font-family', family),
        })),
      },
      '-', 'cut', 'copy', 'paste',
    ],
  },
});

Items that react to the selection

disabled and hidden functions run every time the menu opens, so state is always current:

{
  title: 'Bold the Selection',
  disabled: (editor) => editor.selection.isCollapsed(),
  undo: false, // commands.exec manages its own undo
  action: (editor) => editor.commands.exec('bold'),
}

Different menus for different editors

new FroalaEditor('#comment-box', {
  rangeMenu: { items: ['cut', 'copy', 'paste'], contextual: false },
});

new FroalaEditor('#article-editor', {
  rangeMenu: true, // full standard menu
});

new FroalaEditor('#read-mostly', {
  rangeMenu: false, // native browser menu
});

An item with an icon

{
  title: 'Insert Rule',
  icon: '<svg viewBox="0 0 16 16"><path d="M2 8h12" stroke="currentColor" stroke-width="2"/></svg>',
  command: 'insertHR',
}

TypeScript

The package ships full definitions. The types you will touch most:

TypeWhat it is
RangeMenuOptions The object form of the rangeMenu option.
RangeMenuEntry One entry in items: a string or an item spec.
RangeMenuItemSpec The custom item object described in the item reference.
FroalaEditor The slice of the editor instance RangeMenu drives, since Froala publishes no types of its own.

Framework wrappers

The React, Vue, and Angular wrappers for Froala all accept the same editor options object, so RangeMenu needs no wrapper-specific code. Register once at startup, then pass rangeMenu inside the config you already provide:

import FroalaEditor from 'froala-editor';
import { registerRangeMenu } from 'rangemenu';

registerRangeMenu(FroalaEditor);

// React example
<FroalaEditorComponent config={{ rangeMenu: { items: ['cut', 'copy', 'paste'] } }} />

Versions and updates

A licence covers every 1.x release of RangeMenu and the Froala major versions listed at purchase (currently v4 and v5). New RangeMenu majors are a separate purchase and are only released when a future Froala major requires breaking changes. Your existing version keeps working either way.

Stuck on something the docs do not answer? Email support@rangemenu.com with your order number.