Froala Headless Mode

by Froala_marketing

HTML

<!-- Froala 5.5.0 — Headless mode demo (paste into the JSFiddle HTML pane) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/froala-editor@5.5.0/css/froala_editor.pkgd.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/froala-editor@5.5.0/css/froala_style.min.css">

<main class="demo">
  <header class="demo-head">
    <h1>Froala headless mode</h1>
    <p>Froala runs with <code>headless: true</code>: no built-in toolbar, popups or styling.
       Everything below is <strong>our own UI</strong>, calling the editor's API.</p>
  </header>

  <!-- Our custom toolbar is built from JavaScript into this element -->
  <div id="my-toolbar" class="my-toolbar" aria-label="Custom editor toolbar"></div>

  <!-- The editor itself: just an editable area -->
  <div id="editor">
    <h2>Welcome to a headless editor</h2>
    <p>Select some text, then use the custom buttons above. This editor has
       <em>no toolbar of its own</em>. Every button is plain HTML that calls a Froala API method.</p>
    <ul><li>Lists work</li><li>Undo and redo work</li></ul>
    <table style="width:100%"><tbody>
      <tr><td>Cell A1</td><td>Cell B1</td></tr>
      <tr><td>Cell A2</td><td>Cell B2</td></tr>
    </tbody></table>
    <p>Last paragraph.</p>
  </div>

  <section class="panel">
    <h3>Live HTML output</h3>
    <pre id="output" class="output"></pre>
  </section>
</main>

<script src="https://cdn.jsdelivr.net/npm/froala-editor@5.5.0/js/froala_editor.pkgd.min.js"></script>

CSS

/* Paste into the JSFiddle CSS pane */
* { box-sizing: border-box; }
body { margin: 0; font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; background: #f5f6f8; color: #1f2937; }
.demo { max-width: 1000px; margin: 0 auto; padding: 24px 16px 48px; }
.demo-head h1 { margin: 0 0 4px; font-size: 24px; }
.demo-head p { margin: 0 0 16px; color: #4b5563; }
code { background: #e5e7eb; padding: 1px 5px; border-radius: 4px; font-size: .9em; }

/* ---- Our custom toolbar ---- */
.my-toolbar { display: flex; flex-direction: column; gap: 10px; background: #fff; border: 1px solid #d1d5db;
  border-radius: 10px 10px 0 0; padding: 12px; position: sticky; top: 0; z-index: 5; }
.tb-group { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.tb-label { font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; color: #6b7280; width: 110px; flex-shrink: 0; }
.tb-btn { font: inherit; font-size: 13px; padding: 6px 10px; border-radius: 6px; border: 1px solid #d1d5db; background: #f9fafb; cursor: pointer; }
.tb-btn:hover { background: #eef2ff; border-color: #818cf8; }
.tb-btn.is-active { background: #4f46e5; border-color: #4f46e5; color: #fff; }

/* ---- The editing area: in headless mode, OUR CSS decides how it looks ---- */
#editor { background: #fff; border: 1px solid #d1d5db; border-top: none; border-radius: 0 0 10px 10px; }
#editor .fr-element { padding: 20px 24px; min-height: 260px; font-size: 16px; line-height: 1.6; outline: none; }
#editor .fr-element:focus { box-shadow: inset 0 0 0 2px #c7d2fe; border-radius: 0 0 10px 10px; }
#editor table td { border: 1px solid #d1d5db; padding: 6px 8px; }
#editor blockquote { border-left: 4px solid #818cf8; margin-left: 0; padding-left: 12px; color: #4b5563; }

/* ---- Output panel ---- */
@media (max-width: 720px) { .tb-label { width: 100%; } }
.panel { margin-top: 16px; background: #fff; border: 1px solid #d1d5db; border-radius: 10px; padding: 12px 14px;...

JavaScript

// Froala 5.5.0 — headless mode demo.
// The editor runs with no built-in UI. The toolbar below is our own HTML,
// and every button simply calls a Froala API method.

const outputEl = document.getElementById('output');

function showHTML(editor) {
  outputEl.textContent = editor.html.get();
}

// Ask the user for a link. Returns the trimmed URL, or null if they cancel.
function askForURL(message, example) {
  const url = window.prompt(message, example);
  return url && url.trim() ? url.trim() : null;
}

// ---------------------------------------------------------------------------
// 1. Create the editor in headless mode
// ---------------------------------------------------------------------------
const editor = new FroalaEditor('#editor', {
  // key: 'YOUR_LICENSE_KEY',   // add your license key here if you have one
  headless: true,               // no toolbar, popups or default styling
  htmlExecuteScripts: false,
  placeholderText: 'Start typing…',
  events: {
    initialized: function () {
      showHTML(this);
      buildToolbar(this);
    },
    contentChanged: function () {
      showHTML(this);
    }
  }
});

// ---------------------------------------------------------------------------
// 2. Our own buttons. Each one calls a Froala API method.
// ---------------------------------------------------------------------------
const GROUPS = [
  {
    label: 'Text',
    buttons: [
      { label: 'Bold', active: 'strong', run: e => e.commands.bold() },
      { label: 'Italic', active: 'em', run: e => e.commands.italic() },
      { label: 'Underline', active: 'u', run: e => e.commands.underline() },
      { label: 'Strike', active: 's', run: e => e.commands.strikeThrough() },
      { label: 'Sub', run: e => e.commands.subscript() },
      { label: 'Sup', run: e => e.commands.superscript() },
      { label: 'Clear format', run: e => e.commands.clearFormatting() }
    ]
  },
  {
    label: 'Blocks',
   ...