npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ixhtml

v2.1.0

Published

Ein leichtgewichtiger WYSIWYG-HTML-Editor ohne Laufzeitabhaengigkeiten.

Downloads

309

Readme

ixHTML

ixHTML ist ein leichtgewichtiger WYSIWYG-HTML-Editor in reinem JavaScript. Er hat keine JavaScript-Laufzeitabhaengigkeiten. Die Bootstrap Icons werden beim Erzeugen des ersten Editors ueber ein CDN geladen.

Links werden ueber einen eigenen modalen Dialog eingefuegt und bearbeitet. Dabei lassen sich URL, Anzeigetext, Titel und das Zielfenster festlegen.

Auch der HTML-Quellcode wird in einem eigenen Modal angezeigt. Dort kann er bearbeitet oder ersetzt und anschliessend in den Editor uebernommen werden.

Tabellen lassen sich ueber ein 10 × 8-Auswahlgitter in der Toolbar einfuegen. Ein Ziehen von einer Zelle zu einer anderen markiert immer den vollstaendigen rechteckigen Zellbereich – auch vertikal und diagonal. Eine schwebende Tabellen-Toolbar bietet Aktionen zum Verbinden und Teilen sowie zum Einfuegen und Entfernen von Zeilen und Spalten. Die vier Eckgriffe einer aktiven Tabelle aendern ihre Breite und Hoehe per Drag-and-drop.

Neu in 2.1.0

  • Direkte Editor-Events ueber editor.on(eventName, listener) mit Unsubscribe-Funktion.
  • Umschaltbarer Dark Mode ueber darkMode, setDarkMode() und getDarkMode().
  • Eigene ueberschreibbare --ixhtml-dark-*-Variablen fuer die komplette dunkle Palette.
  • Im Dark Mode umgekehrte, helle Tooltips mit separat konfigurierbarem Hintergrund und Text.

CSS-API und individuelles Design

Der Editor stellt zentrale Designwerte als CSS Custom Properties bereit. Sie koennen direkt am Host gesetzt werden und gelten dadurch nur fuer die jeweilige Instanz:

#editor {
  --ixhtml-primary: #7c3aed;
  --ixhtml-background: #fcfcff;
  --ixhtml-surface-muted: #f4f1ff;
  --ixhtml-text-color: #211a2f;
  --ixhtml-border-color: #d8d0e8;
  --ixhtml-font-family: Inter, sans-serif;
  --ixhtml-font-size: 15px;
  --ixhtml-editor-padding: 24px;
  --ixhtml-toolbar-padding: 10px;
  --ixhtml-table-cell-padding: 12px;
}

Verfuegbar sind ausserdem --ixhtml-muted-color, --ixhtml-surface, --ixhtml-hover-background, --ixhtml-active-background, --ixhtml-control-border-color, --ixhtml-table-border-color, --ixhtml-table-header-background, --ixhtml-selection-background, --ixhtml-border-radius und --ixhtml-line-height.

Dieselben Werte lassen sich bei der Initialisierung oder spaeter per JavaScript setzen. Der Prefix --ixhtml- ist bei den API-Methoden optional:

const editor = new ixHTML(document.getElementById("editor"), {
  css: {
    variables: {
      primary: "#7c3aed",
      borderRadius: "8px"
    },
    rules: {
      editor: { maxWidth: "760px", margin: "0 auto" },
      tableCell: { minWidth: "80px" },
      buttonHover: { transform: "translateY(-1px)" }
    }
  }
});

editor.setCssVariable("primary", "#2563eb");
editor.setCssVariables({ fontSize: "17px", editorPadding: "20px" });
editor.setCssRules({ toolbar: { borderBottomWidth: "2px" } });
console.log(editor.getCssVariable("primary"));
console.log(editor.getCssRules());
editor.resetCss();

Regeln sind absichtlich an stabile Komponentennamen gebunden und werden automatisch auf die aktuelle Editor-Instanz begrenzt. Unterstuetzt werden root, toolbar, editor, footer, button, buttonHover, buttonActive, select, popover, table, tableCell, tableHeader, tableToolbar, tableSelection, resizeHandle, source, tooltip, licenseGate, licenseCard, modalBackdrop, modal, modalHeader, modalBody, modalActions, input und action. Auch ausserhalb des Editor-Containers gerenderte Dialoge werden dabei korrekt ihrer Instanz zugeordnet. CSS-Eigenschaften koennen in camelCase oder kebab-case angegeben werden.

ixHTML.getCssComponents() liefert die verfuegbaren Komponentennamen, ixHTML.getCssVariableDefaults() alle Designvariablen samt Standardwerten.

Dark Mode

Der Dark Mode kann bei der Initialisierung aktiviert und danach jederzeit umgeschaltet werden:

const editor = new ixHTML(element, {
  darkMode: true,
  css: {
    variables: {
      darkPrimary: "#b5a7ff",
      darkBackground: "#0b1210",
      darkSurface: "#121c18"
    }
  }
});

editor.setDarkMode(false);
editor.setDarkMode(true);
console.log(editor.getDarkMode());

Die Dark-Mode-Palette verwendet eigene ueberschreibbare Variablen: --ixhtml-dark-primary, --ixhtml-dark-background, --ixhtml-dark-surface, --ixhtml-dark-surface-muted, --ixhtml-dark-text-color, --ixhtml-dark-muted-color, --ixhtml-dark-hover-background, --ixhtml-dark-active-background, --ixhtml-dark-border-color, --ixhtml-dark-control-border-color, --ixhtml-dark-table-border-color, --ixhtml-dark-table-header-background, --ixhtml-dark-selection-background, --ixhtml-dark-tooltip-background und --ixhtml-dark-tooltip-text-color. Bei den JavaScript-Methoden kann der Prefix entfallen, beispielsweise editor.setCssVariable("darkSurface", "#171f1b"). Tooltips werden im Dark Mode standardmaessig hell mit dunkler Schrift dargestellt.

Als lokales Package verwenden

Das Verzeichnis kann direkt in die package.json eines anderen Projekts eingetragen werden:

{
  "dependencies": {
    "ixhtml": "file:../WYSIWYG"
  }
}

Danach die Abhaengigkeiten mit npm install installieren und den Editor verwenden:

const ixHTML = require("ixhtml");

const editor = new ixHTML(document.getElementById("editor"), {
  licenseKey: "IXH1-...",
  placeholder: "Schreibe etwas...",
  initialHtml: "<p>Hallo!</p>"
});

editor.ready.then(function () {
  console.log(editor.getHtml());
});

Mit einem Bundler ist auch ein ES-Import moeglich:

import ixHTML from "ixhtml";

Der Ziel-Container benoetigt eine Hoehe, damit der Editor sichtbar ist:

#editor {
  width: 100%;
  height: 500px;
}

Lizenzierung

ixHTML 2.x benoetigt immer eine gueltige Lizenz vom fest konfigurierten Lizenzserver https://ixhtml.konzept-ix.com.

const editor = new ixHTML(element, {
  licenseKey: "IXH1-12345-ABCDE-..."
});

await editor.ready;

Ohne licenseKey zeigt der Editor eine lokalisierte Freischaltungsansicht mit Eingabefeld. Vor erfolgreicher Aktivierung sind Inhaltsbereich, Editor-API und Plugins gesperrt.

Der rohe Lizenz-Key wird nicht gespeichert. Nach der Aktivierung wird ausschliesslich das vom Server Ed25519-signierte Token gespeichert. Es ist an die aktuelle Origin und eine zufaellige lokale Installations-ID gebunden. Vorhandene gueltige Tokens werden beim naechsten Laden lokal geprueft und wiederverwendet. Der oeffentliche Pruefschluessel wird aus Sicherheitsgruenden pro Browser-Sitzung erneut ueber HTTPS geladen und nicht dauerhaft als vertrauenswuerdiger Schluessel im Local Storage abgelegt.

editor.getLicenseStatus();
// { status: "active", expiresAt: "...", features: ["editor", "plugins"] }

const success = await editor.activateLicense("IXH1-...");
await editor.deactivateLicense();

Moegliche Zustaende sind locked, checking, active und invalid. Die Lizenzpruefung benoetigt HTTPS; localhost ist fuer lokale Entwicklung ebenfalls geeignet. Direkt ueber file:// geoeffnete Seiten koennen nicht aktiviert werden.

Sprache und Lokalisierung

Die Sprache kann beim Erzeugen des Editors mit locale festgelegt werden:

const editor = new ixHTML(document.getElementById("editor"), {
  locale: "en-US"
});

Regionscodes wie de-DE, en-US, fr-CA oder pt-BR werden automatisch auf eine vorhandene Basissprache aufgeloest. Mitgeliefert werden:

  • de – Deutsch, zugleich Standard
  • en – Englisch
  • fr – Franzoesisch
  • es – Spanisch
  • it – Italienisch
  • pt – Portugiesisch

Die Sprache kann jederzeit ohne Neuaufbau und ohne Inhaltsverlust gewechselt werden:

editor.setLocale("fr");
console.log(editor.getLocale()); // "fr"

Dabei werden Toolbar, Tooltips, Platzhalter, Tabellensteuerung, Link-, Quellcode- und Suchen/Ersetzen-Modals sowie ARIA-Beschriftungen aktualisiert. Ein explizit gesetzter eigener placeholder bleibt bei Sprachwechseln unveraendert.

Alle vorhandenen Sprachen sind abfragbar:

ixHTML.getAvailableLocales(); // ["de", "en", "fr", "es", "it", "pt"]

Weitere Sprachen koennen vor der Editorinitialisierung registriert werden. Fehlende Schluessel fallen automatisch auf Englisch zurueck:

ixHTML.registerLocale("nl", {
  placeholder: "Schrijf iets...",
  undo: "Ongedaan maken",
  redo: "Opnieuw"
});

const editor = new ixHTML(element, { locale: "nl-NL" });

Plugins erhalten mit api.getLocale() den aktuellen Sprachcode und mit api.t(key, values) Zugriff auf die Editor-Uebersetzungen. Auf einen Laufzeitwechsel reagieren sie so:

api.on("localeChange", function (event) {
  console.log(event.locale);
  cancelButton.textContent = api.t("cancel");
});

Plugin-eigene Texte werden nicht automatisch uebersetzt, da deren Bedeutung nur das Plugin kennt. Das WordCount-Beispiel in index.html zeigt ein Plugin mit eigenen Texten fuer alle mitgelieferten Sprachen.

Direkt im Browser verwenden

<div id="editor" style="height: 500px"></div>
<script src="./node_modules/ixhtml/ixhtml.js"></script>
<script>
  const editor = new ixHTML(document.getElementById("editor"), {
    licenseKey: "IXH1-..."
  });

  editor.ready.then(function () {
    console.log("Editor freigeschaltet");
  });
</script>

Toolbar konfigurieren

Alle integrierten Toolbar-Funktionen sind standardmaessig aktiviert. Einzelne Controls koennen beim Initialisieren mit false ausgeblendet oder mit true explizit aktiviert werden:

const editor = new ixHTML(element, {
  licenseKey: "IXH1-...",
  bold: true,
  italic: true,
  underline: false,
  table: false,
  viewSource: false
});

Folgende boolesche Optionen stehen zur Verfuegung:

  • undo, redo
  • bold, italic, underline, strikeThrough
  • fontName, foreColor, formatBlock
  • justifyLeft, justifyCenter, justifyRight, justifyFull
  • insertUnorderedList, insertOrderedList
  • createLink, unlink
  • insertHorizontalRule, removeFormat
  • table, findReplace, viewSource

Mit toolbar werden sowohl die angezeigten Controls als auch deren genaue Reihenfolge festgelegt. separator erzeugt einen visuellen Trenner:

const editor = new ixHTML(element, {
  licenseKey: "IXH1-...",
  toolbar: [
    "formatBlock",
    "separator",
    "bold",
    "italic",
    "foreColor",
    "separator",
    "createLink",
    "table",
    "separator",
    "undo",
    "redo"
  ]
});

Nur Eintraege aus diesem Array werden dargestellt. Ist eine aufgefuehrte Funktion gleichzeitig ueber ihre boolesche Option auf false gesetzt, bleibt sie ausgeblendet. Eine Funktion, die nicht im Array steht, wird auch bei true nicht angezeigt.

API

  • getHtml() liefert den HTML-Inhalt.
  • setHtml(html) ersetzt den Inhalt.
  • setCssVariable(name, value) und setCssVariables(values) setzen Designvariablen fuer diese Instanz.
  • setCssRules(rules) ueberschreibt Styles stabiler Editor-Komponenten.
  • getCssVariable(name) und getCssRules() lesen die wirksame Variable beziehungsweise die gesetzten Komponentenregeln.
  • resetCss() entfernt alle ueber die API gesetzten CSS-Anpassungen.
  • getText() liefert den reinen Text.
  • undo() entfernt das zuletzt abgeschlossene Wort.
  • redo() stellt das zuletzt rueckgaengig gemachte Wort wieder her.
  • focus() fokussiert den Editor.
  • getDarkMode() liefert den aktuellen Darstellungsmodus.
  • setDarkMode(enabled) schaltet den Dark Mode auch nach der Initialisierung um.
  • on(eventName, callback) registriert einen Listener und gibt eine Funktion zum Abmelden zurueck.
  • destroy() entfernt die Editor-Instanz aus dem Container.
  • ready wird aufgeloest, sobald die Lizenz erfolgreich geprueft wurde.
  • activateLicense(key) aktiviert eine gesperrte Instanz.
  • getLicenseStatus() liefert Status, Ablaufzeit und Features.
  • refreshLicense() erneuert das signierte Token.
  • deactivateLicense() entfernt die lokale und serverseitige Aktivierung.

Direkt an der Editorinstanz koennen Aenderungen und Statuswechsel beobachtet werden:

const stopListening = editor.on("change", function (event) {
  console.log(event.html, event.text);
});

editor.on("input", function (event) {
  console.log(event.originalEvent);
});

// Listener spaeter wieder entfernen
stopListening();

Unterstuetzt werden input, change, localeChange, darkModeChange, licenseChange und destroy. input wird unmittelbar bei einer Benutzereingabe ausgeloest. change erfasst jede Aenderung am Editorinhalt, also beispielsweise auch setHtml(), Quellcode-Aenderungen, Links sowie Undo/Redo. darkModeChange liefert den neuen Zustand als event.darkMode.

Die Demo in index.html zeigt die direkte Browser-Verwendung.

Plugins schreiben

Ein Plugin ist eine Setup-Funktion, die einmal unter einem eindeutigen Namen registriert wird. Nur Editorinstanzen, die diesen Namen in plugins angeben, laden das Plugin.

Das folgende Plugin zeigt die aktuelle Wortanzahl in der Toolbar:

ixHTML.registerPlugin("wordCount", function (api, options) {
  const counter = document.createElement("span");
  counter.style.padding = "0 8px";
  counter.style.fontSize = "13px";
  counter.title = options.label || "Wortanzahl";
  api.addFooterControl(counter);

  function update() {
    const text = api.getText().trim();
    const words = text ? text.split(/\s+/).length : 0;
    counter.textContent = words + " Woerter";
  }

  const stopListening = api.on("change", update);
  update();

  return function cleanup() {
    stopListening();
    counter.remove();
  };
});

Das Plugin wird danach beim Erzeugen des Editors aktiviert. Plugin-Optionen sind frei waehlbar und werden unveraendert an das Plugin weitergereicht:

const editor = new ixHTML(document.getElementById("editor"), {
  licenseKey: "IXH1-...",
  plugins: [
    {
      name: "wordCount",
      options: { label: "Woerter im Dokument" }
    }
  ]
});

Ohne Optionen reicht der Plugin-Name:

const editor = new ixHTML(element, {
  licenseKey: "IXH1-...",
  plugins: ["wordCount"]
});

Einen Toolbar-Button hinzufuegen

ixHTML.registerPlugin("insertTimestamp", function (api) {
  api.addToolbarButton({
    title: "Zeitstempel einfuegen",
    icon: "bi-clock",
    separatorBefore: true,
    onClick: function () {
      const value = new Date().toISOString();
      api.insertHtml("<time datetime=\"" + value + "\">" + value + "</time>");
    }
  });
});

icon ist eine Bootstrap-Icons-Klasse. Ohne Icon kann mit text kurzer Buttontext angegeben werden. Mit position: "start" wird das Element am Anfang statt am Ende der Toolbar eingefuegt. separatorBefore: true setzt unmittelbar vor dem Plugin-Element einen optischen Trenner.

Die gleiche Option ist bei freien Toolbar- und Footer-Elementen verfuegbar:

api.addToolbarControl(element, {
  position: "end",
  separatorBefore: true
});

api.addFooterControl(statusElement, {
  separatorBefore: true
});

Die bisherige Kurzform api.addToolbarControl(element, "start") beziehungsweise "end" bleibt weiterhin gueltig.

Ein Plugin-Modal erstellen

api.createModal() erzeugt einen Dialog im Design des Editors. Felder und Buttons werden deklarativ angegeben:

ixHTML.registerPlugin("insertBadge", function (api) {
  const modal = api.createModal({
    title: "Hinweis einfuegen",
    fields: [
      {
        name: "text",
        label: "Text",
        type: "text",
        placeholder: "Hinweistext",
        required: true
      },
      {
        name: "kind",
        label: "Darstellung",
        type: "select",
        options: [
          { label: "Information", value: "info" },
          { label: "Warnung", value: "warning" }
        ]
      },
      {
        name: "important",
        label: "Wichtig",
        type: "checkbox"
      }
    ],
    buttons: [
      {
        label: "Abbrechen",
        closeOnClick: true
      },
      {
        label: "Einfuegen",
        icon: "bi-check-lg",
        submit: true,
        closeOnClick: true,
        onClick: function (values) {
          const badge = document.createElement("span");
          badge.className = "badge badge-" + values.kind;
          badge.textContent = values.text;
          if (values.important) {
            badge.setAttribute("data-important", "true");
          }
          api.insertHtml(badge.outerHTML);
        }
      }
    ]
  });

  api.addToolbarButton({
    title: "Hinweis einfuegen",
    icon: "bi-info-circle",
    separatorBefore: true,
    onClick: function () {
      modal.open({
        text: "",
        kind: "info",
        important: false
      });
    }
  });
});

Unterstuetzte Feldtypen sind text, url, email, number, date, color, textarea, checkbox und select. Felder koennen unter anderem value, placeholder, required, min, max, step und autocomplete erhalten. Fuer komplexe Inhalte kann zusaetzlich ein eigenes DOM-Element als content uebergeben werden.

Der zurueckgegebene Modal-Controller bietet:

  • modal.open(values) und modal.close() zum Oeffnen und Schliessen.
  • modal.getValue(name) und modal.setValue(name, value) fuer einzelne Felder.
  • modal.getValues() und modal.setValues(values) fuer alle Felder.
  • modal.fields fuer direkten Zugriff auf die erzeugten Eingabe-Elemente.
  • modal.element und modal.dialog fuer erweiterte DOM-Anpassungen.
  • modal.destroy() zum manuellen Entfernen. Beim Zerstoeren des Editors geschieht dies automatisch.

Ein Button mit submit: true verwendet die normale Formularvalidierung, beispielsweise fuer required. Mit closeOnClick: true wird das Modal nach erfolgreicher Aktion geschlossen. Gibt onClick den Wert false zurueck, bleibt es geoeffnet. closeOnBackdrop: false und closeOnEscape: false koennen das Schliessen ueber Hintergrund beziehungsweise Escape deaktivieren.

Plugin-API

  • api.editor, api.root und api.toolbar geben Zugriff auf die relevanten DOM-Elemente.
  • api.footerbar gibt direkten Zugriff auf die optionale Statusleiste unter dem Editor. Sie ist ohne Inhalt automatisch unsichtbar.
  • api.getHtml(), api.getText() und api.setHtml(html) lesen oder ersetzen Inhalte.
  • api.getLicenseStatus() liefert den bereits geprueften Lizenzstatus. Plugins starten erst nach erfolgreicher Lizenzpruefung.
  • api.insertHtml(html) fuegt HTML an der aktuellen Cursorposition ein und legt einen Undo/Redo-Schritt an.
  • api.exec(command, value) fuehrt einen vorhandenen Editorbefehl aus.
  • api.addToolbarButton(config) erzeugt einen Button im Design des Editors.
  • api.addToolbarControl(element, options) nimmt ein beliebiges eigenes DOM-Element in die Toolbar auf.
  • api.addFooterControl(element, options) nimmt ein eigenes Status- oder Anzeigeelement in die Footerbar auf.
  • api.createModal(config) erstellt ein Plugin-Modal mit Feldern, Selects und Aktionsbuttons.
  • api.on("input", callback) reagiert unmittelbar auf Benutzereingaben.
  • api.on("change", callback) reagiert auf jede DOM-Inhaltsaenderung, auch durch Quellcode, Links oder Undo/Redo.
  • api.on("licenseChange", callback) reagiert auf eine spaetere Deaktivierung oder erneute Freischaltung.
  • api.on("destroy", callback) reagiert auf das Entfernen der Editorinstanz.
  • api.saveHistory() speichert direkte DOM-Aenderungen eines Plugins als Undo/Redo-Schritt.

Die Setup-Funktion kann eine Cleanup-Funktion oder ein Objekt mit destroy() zurueckgeben. Dieses Cleanup wird automatisch durch editor.destroy() ausgefuehrt. HTML, das ein Plugin mit setHtml oder insertHtml einfuegt, gilt als vertrauenswuerdig; falls es von Benutzern oder externen Quellen stammt, sollte das Plugin es vorher bereinigen.

Im Browser muss die Plugin-Datei nach ixhtml.js, aber vor der Editorinitialisierung geladen werden. In einem Bundler wird zuerst ixHTML importiert, danach das Plugin registriert und anschließend die Editorinstanz erzeugt.