PHPackages                             tobento/js-editor - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. tobento/js-editor

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

tobento/js-editor
=================

Simple JavaScript WYSIWYG HTML Editor with inlined toolbar only.

1.0.2(1y ago)237↓33.3%12MITJavaScript

Since Feb 27Pushed 1y ago1 watchersCompare

[ Source](https://github.com/tobento-ch/js-editor)[ Packagist](https://packagist.org/packages/tobento/js-editor)[ Docs](https://www.tobento.ch)[ RSS](/packages/tobento-js-editor/feed)WikiDiscussions 1.x Synced 1mo ago

READMEChangelog (3)DependenciesVersions (4)Used By (2)

JS Editor
=========

[](#js-editor)

Simple JavaScript WYSIWYG HTML Editor with inlined toolbar only.

The editor does not style the content by using inline style attributes. Instead it uses classes only. This has multiple advantages:

- easily customize content by its classes
- using strong Content-Security-Policy blocking style-src
- limits user to keep corporate design

You may visit the [**docs.tobento.ch/js-editor**](https://docs.tobento.ch/js-editor) page for demo.

Table of Contents
-----------------

[](#table-of-contents)

- [Getting started](#getting-started)
    - [Browser support](#browser-support)
- [Documentation](#documentation)
    - [Basic Usage](#basic-usage)
    - [Custom Editor](#custom-editor)
    - [Available Plugins](#available-plugins)
        - [Basic Plugins](#basic-plugins)
        - [Table Plugin](#table-plugin)
        - [Styles Plugin](#styles-plugin)
    - [Create Plugin](#create-plugin)
    - [Events](#events)
        - [Global Events](#global-events)
        - [Editor Events](#editor-events)
    - [API](#api)
        - [Editors API](#editors-api)
        - [Editor API](#editor-api)
        - [Events API](#events-api)
        - [Selection API](#selection-api)
        - [Toolbars API](#toolbars-api)
        - [Toolbar API](#toolbar-api)
        - [Translator API](#translator-api)
- [Credits](#credits)

---

Getting started
===============

[](#getting-started)

Browser support
---------------

[](#browser-support)

Modern browser only.

Documentation
=============

[](#documentation)

Basic Usage
-----------

[](#basic-usage)

**1. Include JS/CSS**

```

```

**2. Register**

```

```

Thats all.

**You may get the HTML code**

Example using the editors:

```

    import editors from 'core/editors.js';

    document.addEventListener('DOMContentLoaded', (e) => {
        const fooEditorCode = editors.get('foo').code();
        const barEditorCode = editors.get('bar').code();
    });

```

Example using events:

```

    import events from 'core/events.js';

    events.listen('editor.blur', (e, editor) => {
        const code = editor.code();
    });

```

Custom Editor
-------------

[](#custom-editor)

You may create a custom editor:

**1. Create `custom-editor.js`**

```
import editors from './core/editors.js';
import translator from './core/translator.js';
import table from './plugin/table.js';
import styles from './plugin/styles.js';
import { basic, html, clear, links } from './plugin/basic.js';

// you may add translations:
translator.locale('de-CH');
// or translator.locale(document.querySelector('html').getAttribute('lang'));
translator.localeFallbacks({"de-CH": "en"});
translator.add('de-CH', {
    "Start typing something...": "Start mit schreiben...",
    "Table": "Tabelle",
    "Add row below": "Zeile danach einfügen",
    "Add row above": "Zeile davor einfügen",
    "Delete row": "Zeile löschen",
    "Add column left": "Spalte links einfügen",
    "Add column right": "Spalte rechts einfügen",
    "Delete column": "Spalte löschen",
    "Delete table": "Tabelle löschen"
});

// you may add styles:
styles.add({
    key: "style.fonts",
    title: "Font styles",
    options: {
        "Default Font": "",
        "Primary Font": "font-primary",
        "Secondary Font": "font-secondary"
    },
    optionToClass: true
});

// add plugins:
editors.plugins([basic, html, clear, links, table, styles]);

// editors:
document.addEventListener('DOMContentLoaded', (e) => {
    // init the editors:
    editors.init();

    // you may auto register editors with the data-editor attribute:
    editors.register();

    // or you may create it manually:
    const editor = editors.create(document.querySelector('#editor'), {
        // config (optional):
        id: 'foo',
        toolbar: ['p', 'bold', 'headings']
    });
});
```

**2. Replace default editor with custom editor**

```

```

Available Plugins
-----------------

[](#available-plugins)

### Basic Plugins

[](#basic-plugins)

```
import editors from './core/editors.js';
import { basic, html, clear, links } from 'plugin/basic.js';

editors.plugins([basic, html, clear, links]);
```

#### Basic Plugin

[](#basic-plugin)

**The `basic` plugin provides the following toolbars:**

`["p", "h1", "h2", "h3", "h4", "h5", "h6", "bold", "italic", "underline", "strike", "ol", "ul", "quote", "pre", "code", "undo", "redo"]`

KEYHTML ElementDescription`p```-`h1```-`h2```-`h3```-`h4```-`h5```-`h6```-`headings`-Opens a toolbar with h1-h6.`bold```-`italic```-`underline```-`strike```-`ol```-`ul```-`quote```-`pre```-`code```-`undo`-Undo last step`redo`-Redo last step`|`-Horizontal line separator`||`-Horizontal space separator`_`-Vertical line separator`__`-Vertical space separator`back`-Back to last toolbar#### Html Plugin

[](#html-plugin)

**The `html` plugin provides the following toolbars:**

`["sourcecode"]`

KEYHTML ElementDescription`sourcecode`-To switch between source code and normal view.#### Clear Plugin

[](#clear-plugin)

**The `clear` plugin provides the following toolbars:**

`["clear"]`

KEYHTML ElementDescription`clear`-To clear the editable area.#### Links Plugin

[](#links-plugin)

**The `links` plugin provides the following toolbars:**

`["link"]`

KEYHTML ElementDescription`link```To insert a link.**Customize link classes**

```
import events from './../events.js';

events.listen('toolbars.item', (item) => {
    if (item.key === 'link.class') {
        item.options = {
            "none": "",
            "default": "button",
            "default fit": "button fit"
        };
    }
});
```

### Table Plugin

[](#table-plugin)

```
import editors from './core/editors.js';
import table from 'plugin/table.js';

editors.plugins([table]);
```

**The `table` plugin provides the following toolbars:**

`["tables"]`

KEYHTML ElementDescription`tables```To add tables.### Styles Plugin

[](#styles-plugin)

The styles plugin adds/removes classe(s) to your selected text.

```
import editors from './core/editors.js';
import styles from 'plugin/styles.js';

// add your styles:
styles.add({
    key: "style.fonts",
    title: "Font styles",
    options: {
        "Default Font": "",
        "Primary Font": "font-primary",
        "Secondary Font": "font-secondary"
    },
    optionToClass: true
});
styles.add({
    key: "style.text.colors",
    title: "Text Colors",
    options: {
        "Default Text Color": "",
        "Text Color Success": "text-success"
    },
    optionToClass: true
});

// add plugin:
editors.plugins([styles]);
```

**Toolbars:**

The style `key` will be your toolbar key:

`["style.fonts", "style.text.colors"]`

Create Plugin
-------------

[](#create-plugin)

Check out the `plugin/table.js` or `plugin/basic.js` file to see how a plugin is created.

Events
------

[](#events)

### Global Events

[](#global-events)

You may use the available events for plugin creation e.g.

**Editors Events**

EventCallback ParametersDescription`editors.init``(editors)`Triggered when the editors.init() function has been called.`editors.registered``(editors)`Triggered after the editors.register() function has been called.```
import events from 'core/events.js';

events.listen('editors.init', (editors) => {
    //
});
```

**Editor Events**

EventCallback ParametersDescription`editor.blur``(event, editor)`Triggered by the blur event of the editor element (editable area).`editor.click``(event, editor)`Triggered by the click event of the editor element (editable area).`editor.created``(editor)`Triggered when the editor has been created.`editor.focus``(event, editor)`Triggered when the editor is focused.`editor.mousedown``(event, editor)`Triggered by the mousedown event of the editor element (editable area).`editor.mouseup``(event, editor)`Triggered by the mouesup event of the editor element (editable area).`editor.keydown``(event, editor)`Triggered by the keydown event of the editor element (editable area).`editor.keypress``(event, editor)`Triggered by the keypress event of the editor element (editable area).`editor.keyup``(event, editor)`Triggered by the keyup event of the editor element (editable area).Example:

```
import events from 'core/events.js';

events.listen('editor.blur', (event, editor) => {
    //
});
```

**Toolbars Events**

EventCallback ParametersDescription`toolbars.item``(item)`Triggered when a toolbars item is added.Example:

```
import events from 'core/events.js';

events.listen('toolbars.item', (item) => {
    if (item.key === 'link.class') {
        item.options = {
            "none": "",
            "default": "button",
            "default fit": "button fit"
        };
    }
});
```

**Toolbar Events**

EventCallback ParametersDescription`toolbar.build``(data)`Triggered when a toolbar is being build.`toolbar.opened``(toolbar)`Triggered after toolbar is opened.`toolbar.closed``(toolbar)`Triggered after toolbar is closed.Example:

```
import events from 'core/events.js';

events.listen('toolbar.build', (data) => {
    // customize link toolbar
    if (toolbar.id === 'link') {
        data.items = [
            'back', 'link.visit', 'link.delete', 'link.insert', '_',
            'link.input', '_',
            'link.window', 'link.windowLabel', '_',
            //'link.class'
        ];
    }
});
```

### Editor Events

[](#editor-events)

EventCallback ParametersDescription`blur``(event, editor)`Triggered by the blur event of the editor element (editable area).`click``(event, editor)`Triggered by the click event of the editor element (editable area).`created``(editor)`Triggered when the editor has been created.`focus``(event, editor)`Triggered when the editor is focused.`mousedown``(event, editor)`Triggered by the mousedown event of the editor element (editable area).`mouseup``(event, editor)`Triggered by the mouesup event of the editor element (editable area).`keydown``(event, editor)`Triggered by the keydown event of the editor element (editable area).`keypress``(event, editor)`Triggered by the keypress event of the editor element (editable area).`keyup``(event, editor)`Triggered by the keyup event of the editor element (editable area).Example:

```
import editors from './core/editors.js';

document.addEventListener('DOMContentLoaded', (e) => {
    // create
    editors.create(document.querySelector('#editor'), {
        events: {
            click: (event, editor) => {
                //
            }
        }
    });
});
```

API
---

[](#api)

### Editors API

[](#editors-api)

```
import editors from './core/editors.js';
```

**init/register**

```
// init the editors:
editors.init();

// you may auto register editors with the data-editor attribute:
editors.register();
```

**create**

Creating a new editor.

```
const editor = editors.create(document.querySelector('#editor'));

// with config:
const editor = editors.create(document.querySelector('#editor'), {
    id: 'foo',
    toolbar: ['p', 'bold', 'headings'],
    events: {
        click: (event, editor) => {
            //
        }
    }
});
```

**has / get / all**

```
if (editors.has('ID')) {
    const editor = editors.get('ID');
}

const allEditors = editors.all();
```

**plugin / plugins**

```
editors.plugin({
    name: 'foo',
    init: () => {
        //
    },
    events: {
        //
    }
});

editors.plugins([{name: 'foo'}, {name: 'bar'}]);
```

### Editor API

[](#editor-api)

```
import editors from './core/editors.js';

const editor = editors.create(document.querySelector('#editor'));
```

**code**

Get the HTML code.

```
const htmlCode = editor.code();
```

**config**

Get config value with dot notation.

```
const value = editor.config('foo.bar', 'default');
```

**Misc**

```
const id = editor.id;
const el = editor.el; // editable area
const selection = editor.selection;
const toolbar = editor.toolbar;
const events = editor.events;
```

- `selection` check out the [Selection API](#selection-api) for more information.
- `toolbar` check out the [Toolbar API](#toolbar-api) for more information.
- `events` check out the [Events API](#events-api) for more information.

### Events API

[](#events-api)

```
import events from './core/events.js';
```

**listen / fire**

```
// with array params:
events.listen('click', (foo, bar) => {});
events.fire('click', ['foo', 'bar']);

// or with object params:
events.listen('click', (obj) => {});
events.fire('click', {});
```

**register**

```
const listeners = {
    "eventName": () => {

    },
};

events.register(listeners);
```

### Selection API

[](#selection-api)

```
import editors from './core/editors.js';

const editor = editors.create(document.querySelector('#editor'));
const selection = editor.selection;
```

**get**

Get the selected data:

```
const sel = selection.get();

const text = sel.text;
const element = sel.element;
const tagName = sel.tagName;
```

**getTagnames**

Get the selected tag names:

```
const tagnames = selection.getTagnames();
```

**Misc**

```
// Saves the current selection with unwrapping a HTML  marker.
selection.save();

// Saves the current selection without unwrapping a HTML  marker.
selection.save(false);

// Set saved selection by element.
selection.setSaved(element, '');

// Get the saved selection.
const sel = selection.getSaved();

// Clears the selection. Removes the marker if any.
selection.clear();

// Replaces the selection marker with the node.
selection.replace(node);

// Replaces the sel with the node.
selection.insertReplace(sel, node);

// Inserts the node after the sel.
selection.insertAfter(sel, node);
```

### Toolbars API

[](#toolbars-api)

```
import toolbars from './core/toolbars.js';
```

**addItem**

Add an item to be later used to build a toolbar.

Example Button:

```
toolbars.addItem({
    // required:
    key: "Foo", // a unique key
    text: "Foo",
    command: ["formatblock", ""],
    undo: ["formatblock", ""], // or null
    tagname: "h2", // used for setting button active
});
```

Example Input:

```
toolbars.addItem({
    // required:
    key: "email", // a unique key
    // optional:
    element: "input", // HTML element, default "button"
    type: "email",
    id: "foo",
    for: "id",
    name: "foo",
    title: "Type your email",
    placeholder: "Type...",
    classes: ["foo", "bar"],
    // options: {"name": "value"}, // for selection element.
    attributes: {"name": "value"}, // any additonal HTML element attributes
    build_default: false, // if to build on default
    click: (event, item, toolbar, editor) => {
        // do something on click
    },
    keyup: (event, item, toolbar, editor) => {
        // do something on keyup
    }
});
```

**Misc**

```
const toolbar = toolbars.create({id: 'ID'});

if (toolbars.has('ID')) {
    const toolbar = toolbars.get('ID');
}

// opens the toolbar if exists:
toolbars.open('ID');

// closes all toolbars:
toolbars.close();

// closes all toolbars except those specified:
toolbars.close(["links"]);
```

### Toolbar API

[](#toolbar-api)

```
import toolbars from './core/toolbars.js';
```

**build**

Build toolbar with the specified items.

```
const toolbar = toolbars.create({id: 'ID'});

toolbar.build([
    'back', 'table.delete', '_',
    'table.row.below', 'table.row.above', 'table.row.delete', '_',
    'table.col.left', 'table.col.right', 'table.col.delete'
]);
```

**open / close**

```
const toolbar = toolbars.get({id: 'ID'});

toolbar.open();
toolbar.close();
```

**Items**

```
const toolbar = toolbars.get({id: 'ID'});

if (toolbar.has('key')) {
    const item = toolbar.get('key');
}

toolbar.disable('key');
toolbar.disable('key', false); // without hiding
toolbar.disableExcept(['key']);
toolbar.disableExcept(['key'], false); // without hiding
toolbar.enable('key');

toolbar.setActive(['key']);
toolbar.setActive(['a', 'p'], 'tagname'); // based on item tagname
toolbar.setActive(['key', 'key', false]); // without setting others inactive
toolbar.setActiveItem('key'); // set only active.

toolbar.positioning(); // position to selection;
toolbar.positioning(event); // position to event.pageX and event.pageY
toolbar.positioning(null, 100, 200); // position to x: 100, y: 200
toolbar.positioning(null, null, null, true); // position to last position
```

### Translator API

[](#translator-api)

```
import translator from './core/translator.js';
```

```
translator.locale('de-CH'); // current locale
translator.localeFallbacks({"de-CH": "en"});

// add translation for the specified locale.
translator.add('de-CH', {
    "Table": "Tabelle"
});

const translated = translator.trans('Table');
```

Credits
=======

[](#credits)

- [Tobias Strub](https://www.tobento.ch)
- [All Contributors](../../contributors)

###  Health Score

29

—

LowBetter than 59% of packages

Maintenance40

Moderate activity, may be stable

Popularity13

Limited adoption so far

Community12

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~89 days

Total

4

Last Release

544d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/055d6a1b5c2384bb179c75ab0b55914231d898fdc4dffeb30770f81200e52206?d=identicon)[TOBENTOch](/maintainers/TOBENTOch)

---

Top Contributors

[![tobento-ch](https://avatars.githubusercontent.com/u/16684832?v=4)](https://github.com/tobento-ch "tobento-ch (3 commits)")

---

Tags

wysiwygtobentohtml editor

### Embed Badge

![Health badge](/badges/tobento-js-editor/health.svg)

```
[![Health](https://phpackages.com/badges/tobento-js-editor/health.svg)](https://phpackages.com/packages/tobento-js-editor)
```

###  Alternatives

[froala/wysiwyg-editor

A beautiful jQuery WYSIWYG HTML rich text editor. High performance and modern design make it easy to use for developers and loved by users.

5.4k306.9k3](/packages/froala-wysiwyg-editor)[yiidoc/yii2-redactor

Extension redactor for Yii2 Framework.

191618.8k47](/packages/yiidoc-yii2-redactor)[ckeditor/ckeditor

JavaScript WYSIWYG web text editor.

5234.2M76](/packages/ckeditor-ckeditor)[tinymce/tinymce

Web based JavaScript HTML WYSIWYG editor control.

1697.5M106](/packages/tinymce-tinymce)[stfalcon/tinymce-bundle

This Bundle integrates TinyMCE WYSIWYG editor into a Symfony2 project.

2692.9M24](/packages/stfalcon-tinymce-bundle)[unisharp/laravel-ckeditor

JavaScript WYSIWYG web text editor (for laravel).

377762.3k5](/packages/unisharp-laravel-ckeditor)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
