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.
| Key | Type | Default | What it does |
|---|---|---|---|
items | array | standard set | The menu, top to bottom. See Menu items. |
contextual | boolean | true |
Prepend table, image, and link sections when you right-click those elements. See Contextual sections. |
theme | string | 'auto' |
'light', 'dark', or
'auto' (follows the operating system, like native
menus). |
zIndex | number | 2147483000 |
Stacking level of the menu. |
onShow | function | Called with the editor when the menu opens. | |
onHide | function | 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:
- A built-in item:
'cut','copy','paste', or'selectAll'. These come with platform-aware shortcut hints. - A named item you registered with
registerRangeMenuItem. - 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
| Field | Type | What it does |
|---|---|---|
title | string | Display text. Required. Translated through the editor's
language pack unless translate: false. |
action | function | Runs on activation, receiving (editor, item). |
command | string | Name of a registered Froala command to run instead of
action. The item is dropped if the command is not
available on this editor. |
items | array | Submenu entries. When present, action and
command are ignored. |
icon | string | Inline SVG markup shown before the title. |
shortcut | string | Right-aligned hint text such as '⌘K'. Display
only; RangeMenu does not bind the key. |
disabled | boolean or function | Greys the item out. Functions receive the editor and are evaluated every time the menu opens. |
hidden | boolean or function | Removes the item entirely. Same evaluation rules as
disabled. |
undo | boolean | 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. |
translate | boolean | 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 target | Needs plugin | Items |
|---|---|---|
| Inside a table cell | table |
Table submenu: insert row above/below, insert column before/after, delete row, delete column, delete table. |
| An image | image |
Image submenu: remove image. |
| A link | link |
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:
| Type | What 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.