Summernote Integration with Laravel Blade

5 Min
880 Words
Abdul Wahab

Summernote is a powerful, free, and lightweight WYSIWYG editor that works exceptionally well for rich text editing in modern web applications. It is especially popular in Laravel-based projects due to its simplicity, flexibility, and ease of integration.

However, integrating Summernote into a Laravel Blade boilerplate can become a bit challenging—particularly when you want to set it up without relying on a CDN. In a local or production-grade setup, you need to manually manage all required CSS and JavaScript dependencies, which adds extra configuration overhead. Since Summernote is tightly coupled with Bootstrap, ensuring proper loading order and compatibility becomes crucial.

The challenge increases further if your Laravel project is built using Tailwind CSS. Tailwind and Bootstrap follow very different design philosophies, and as a result, they often override each other’s utility classes and base styles. This can lead to unexpected UI issues such as broken layouts, inconsistent spacing, or misaligned components—making styling and layout management quite frustrating without proper isolation.

Another common pain point is Bangla (Bengali) language support. While Summernote technically supports Unicode, configuring it to work smoothly with Bangla input can sometimes be tricky. Issues may arise with font rendering, line spacing, or copy-paste behavior from Bangla sources, especially if proper fonts and encoding are not carefully handled during setup.

Despite these challenges, with the right configuration and careful dependency management, Summernote performs beautifully. It delivers a professional-level rich text editing experience that is perfectly suitable for blogs, CMS panels, and admin dashboards in Laravel applications.

In this blog, a detailed step-by-step guide is provided on how to properly set up Summernote inside a Laravel Blade template, handle Bootstrap and Tailwind conflicts, enable Bangla-friendly text input, and organize assets without using a CDN.

Installation & Setup

Install via npm/yarn

npm install summernote
# or
yarn add summernote

Summernote Textarea for Editor view

<div class="bg-white">
  <textarea
    name="description"
    class="summernote-editor summernote"
    id="summernote-editor"
  >
{{ old('description') }}</textarea
  >
</div>

JavaScript Setup for Editor

import $ from "jquery";
window.$ = window.jQuery = $;
import "summernote";
import "summernote/dist/summernote-lite.css";
import "summernote/dist/summernote-lite.js";

$(document).ready(function () {
  // First check if the element exists
  const editorElement = document.getElementById("summernote-editor");

  if (!editorElement) {
    const editorByClass = document.querySelector(".summernote-editor");
    if (editorByClass) {
      editorByClass.id = "summernote-editor";
    } else {
      return; // Exit if no editor element found
    }
  }

  // Get CSRF token for Laravel
  const csrfToken = document
    .querySelector('meta[name="csrf-token"]')
    .getAttribute("content");

  // Now initialize Summernote
  try {
    $("#summernote-editor").summernote({
      height: 400,
      minHeight: 200,
      maxHeight: 800,
      focus: true,
      placeholder: "Write content here...",
      tabsize: 2,
      toolbar: [
        ["style", ["style"]],
        [
          "font",
          ["bold", "italic", "underline", "strikethrough", "clear", "fontname"],
        ],
        ["fontsize", ["fontsize"]],
        ["color", ["color"]],
        ["para", ["ul", "ol", "paragraph"]],
        ["table", ["table"]],
        ["insert", ["link", "picture", "video"]],
        ["code", ["codeview", "pre"]],
        ["history", ["undo", "redo"]],
      ],
      fontSizes: ["8", "9", "10", "11", "12", "14", "16", "18", "20", "22", "24", "28", "32", "36", "48", "64", "72",
      ],
      fontNames: ["Kalpurush", "Noto Sans Bengali"],
      callbacks: {
        onImageUpload: function (files) {
          for (let i = 0; i < files.length; i++) {
            uploadImage(files[i], this);
          }
        },
        onInit: function () {
          const content = $("#summernote-editor").summernote("code");
          $("#summernote-editor").summernote(
            "code",
            content.replace(/&lt;|&gt;/g, "")
          );
        },
        onPaste: function (e) {
          const bufferText = (
            (e.originalEvent || e).clipboardData || window.clipboardData
          ).getData("Text");
          e.preventDefault();
          document.execCommand("insertText", false, bufferText);
        },
      },
      styleTags: [
        "p",
        {
          title: "Blockquote",
          tag: "blockquote",
          className: "blockquote",
          value: "blockquote",
        },
        "h1", "h2", "h3", "h4", "h5", "h6", {
          title: "Code Block",
          tag: "pre",
          className: "code-block",
          value: "pre",
        },
      ],
      popover: {
        image: [
          [
            "image",
            ["resizeFull", "resizeHalf", "resizeQuarter", "resizeNone"],
          ],
          ["float", ["floatLeft", "floatCenter", "floatRight"]],
          ["remove", ["removeMedia"]],
        ],
      },
      buttons: {
        floatCenter: function (context) {
          const ui = $.summernote.ui;
          const svgIcon = `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"></svg>`;
          return ui
            .button({
              contents: svgIcon,
              tooltip: "Align Center",
              click: function () {
                const $selectedImage = $(
                  context.invoke("editor.restoreTarget")
                ).closest("img");
                if ($selectedImage.length) {
                  $selectedImage
                    .removeClass("note-align-left note-align-right")
                    .addClass("note-align-center")
                    .css({
                      display: "block",
                      marginLeft: "auto",
                      marginRight: "auto",
                      float: "none",
                    });
                } else {
                  alert("Please select an image to align center!");
                }
              },
            })
            .render();
        },
      },
      styleWithSpan: true,
      disableDragAndDrop: false,
      shortcuts: false,
      tableClassName: "table table-bordered",
    });
  } catch (error) {}

  function uploadImage(file, editor) {
    const formData = new FormData();
    formData.append("file", file);
    $.ajax({
      url: "/admin/upload/image",
      method: "POST",
      data: formData,
      contentType: false,
      processData: false,
      headers: { "X-CSRF-TOKEN": csrfToken },
      success: function (data) {
        $(editor).summernote("insertImage", data.url);
      },
      error: function (err) {
        alert(
          "Failed to upload image: " +
            (err.responseJSON ? err.responseJSON.error : "Unknown error")
        );
      },
    });
  }

  $("form").on("submit", function () {
    try {
      const content = $("#summernote-editor").summernote("code");
      $("#summernote-editor").summernote(
        "code",
        content.replace(/&lt;|&gt;/g, "")
      );
    } catch (error) {
      console.error("Error during form submission:", error);
    }
  });
});

Display Content Safely

Show Post Blade Template

<div class="flex flex-col justify-between">
  <div class="text-lg text-justify note-editable">
    {!! $blog->description !!}
  </div>
</div>

Custom Themes and Styling add for Display Content

/* Custom Summernote styling */
.note-editor.note-frame {
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.note-toolbar {
  background-color: #f8f9fa;
  border-bottom: 1px solid #dee2e6;
}

.note-editable {
  min-height: 300px;
  font-size: 16px;
  line-height: 1.6;
}

.note-status-output {
  background-color: #f8f9fa;
  border-top: 1px solid #dee2e6;
}

Conclusion

This comprehensive guide covers everything you need to integrate Summernote with Laravel Blade effectively. From basic setup to advanced features like image uploads, auto-save functionality, and custom buttons, you now have a complete WYSIWYG editor solution for your Laravel applications.

Remember to always prioritize security when handling user-generated content, and regularly update your dependencies to ensure you have the latest security patches and features.

Happy coding!