nasirkhan/laravel-jodit

Jodit WYSIWYG editor integration for Laravel — works with Blade, Blade Components, and Livewire

Maintainers

Package info

github.com/nasirkhan/laravel-jodit

pkg:composer/nasirkhan/laravel-jodit

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-03-22 15:29 UTC

This package is auto-updated.

Last update: 2026-03-22 15:54:55 UTC


README

A Laravel package that integrates the Jodit WYSIWYG editor via a reusable Blade component. Works seamlessly in plain Blade templates, Blade view components, and Livewire components, with a built-in server-side file browser/uploader connector.

This package is used in Laravel Starter though it is framework-agnostic and can be dropped into any Laravel app.

Features

  • One Blade component<x-jodit::editor name="content" /> covers all use cases
  • Livewire-ready — pass wire-model and the editor syncs with your Livewire component
  • File browser + uploads — bundled connector controller; configurable storage disk and path
  • CDN assets — loads Jodit CSS/JS from unpkg; no build step required
  • Fully configurable — publish the config to override defaults, CDN URLs, middleware, etc.

Requirements

  • PHP 8.2+
  • Laravel 11/ 12/ 13
  • intervention/image-laravel ^1.5 — only required for image resize and crop features

Installation

composer require nasirkhan/laravel-jodit

The service provider is auto-discovered. Optionally publish the config:

php artisan vendor:publish --tag=jodit-config

Usage

1. Ensure your layout has asset stacks

Your main layout must include the stacks that the component pushes assets into.
The default stack names are after-styles (CSS) and after-scripts (JS).
Add these to your layout if they are not already present:

{{-- In <head> --}}
@stack('after-styles')

{{-- Before </body> --}}
@stack('after-scripts')

You can change the stack names in config/jodit.php.

2. Drop the component into any form

Plain Blade

<x-jodit::editor name="content" :value="old('content', $post->content ?? '')" />

With required + placeholder

<x-jodit::editor
    name="content"
    :value="old('content')"
    placeholder="Write your post here…"
    :required="true"
/>

Livewire — two-way sync

<x-jodit::editor name="content" :value="$content" wire-model="content" />

Inside a Livewire component the wrapper is automatically set to wire:ignore so Livewire's DOM diffing does not destroy the editor. Changes are flushed back to the Livewire component via the JavaScript API with a 300 ms debounce.

Disable file browser

<x-jodit::editor name="excerpt" :file-browser="false" />

Custom height and connector URL

<x-jodit::editor
    name="body"
    :height="600"
    connector-url="{{ route('admin.jodit.connector') }}"
/>

Component Props

Prop Type Default Description
name string <textarea name> / form field name (required)
id string jodit_{name} Custom HTML id for the textarea
value string '' Initial HTML content
placeholder string null Textarea placeholder
class string '' Extra CSS classes on the textarea
height int config default (400) Editor height in pixels
file-browser bool true Enable Jodit file browser / uploader
connector-url string auto from config Override the connector endpoint URL
wire-model string null Livewire model property to keep in sync
required bool false Add required attribute to the textarea
buttons array|string config default Custom toolbar button list (see Buttons Reference)
debounce int 300 Livewire sync debounce in milliseconds

Passing buttons

You can pass the buttons prop as a PHP array (:buttons=), a JSON string, or a PHP-style array string:

{{-- PHP array (recommended) --}}
<x-jodit::editor name="content" :buttons="['bold', 'italic', 'underline', '|', 'link', 'image']" />

{{-- PHP-style array string (no colon prefix needed) --}}
<x-jodit::editor name="content" buttons="['bold', 'italic', 'underline', '|', 'link', 'image']" />

{{-- JSON string --}}
<x-jodit::editor name="content" buttons='["bold", "italic", "underline", "|", "link", "image"]' />

Configuration

// config/jodit.php (after publishing)

return [
    // Jodit CDN URLs — change the version or point to a custom build
    'cdn_css' => 'https://unpkg.com/jodit@4.1.16/es2021/jodit.min.css',
    'cdn_js'  => 'https://unpkg.com/jodit@4.1.16/es2021/jodit.min.js',

    // Asset stacks used by the Blade component
    'assets' => [
        'styles_stack'  => 'after-styles',
        'scripts_stack' => 'after-scripts',
    ],

    // Connector route settings
    'route' => [
        'enabled'    => true,
        'prefix'     => 'jodit',
        'name'       => 'jodit.connector',
        'middleware' => ['web', 'auth'],
    ],

    // Storage
    'disk'      => 'public',
    'base_path' => 'jodit',

    // Upload constraints
    'max_file_size'  => 10240,   // kilobytes
    'allowed_mimes'  => 'jpeg,jpg,png,gif,webp,svg,pdf,doc,docx,xls,xlsx,zip,txt',

    // Default editor options (passed directly to Jodit)
    'defaults' => [
        'height'               => 400,
        'toolbarSticky'        => true,
        'toolbarButtonSize'    => 'large',
        'showCharsCounter'     => false,
        'showWordsCounter'     => false,
        'showXPathInStatusbar' => false,
        'defaultActionOnPaste' => 'insert_clear_html',
    ],

    // Default toolbar buttons
    'buttons' => [
        'bold', 'italic', 'underline', 'strikethrough', '|',
        'left', 'center', 'right', '|',
        'ul', 'ol', '|',
        'font', 'fontsize', 'paragraph', 'brush', '|',
        'link', 'image', 'video', 'file', '|',
        'undo', 'redo',
    ],
];

Registering the connector under a custom route

If you want the connector to live under your admin prefix with your own middleware, disable the package route and register it yourself:

// config/jodit.php
'route' => [
    'enabled' => false,
],
// routes/web.php
use Nasirkhan\LaravelJodit\Http\Controllers\JoditConnectorController;

Route::middleware(['web', 'auth', 'role:admin'])
    ->prefix('admin')
    ->group(function () {
        Route::any('jodit-connector', [JoditConnectorController::class, 'handle'])
            ->name('backend.jodit.connector');
    });

Then tell the component which route to use:

<x-jodit::editor
    name="content"
    connector-url="{{ route('backend.jodit.connector') }}"
/>

Or set a global default in config/jodit.php:

'route' => [
    'enabled' => false,
    'name'    => 'backend.jodit.connector',  // used by component when no connector-url prop
],

Buttons Reference

Use any of the names below in your buttons array. Use | as a visual separator between groups.

Text Formatting

Name Description
bold Bold
italic Italic
underline Underline
strikethrough Strikethrough
superscript Superscript
subscript Subscript
eraser Clear formatting

Alignment

Name Description
left Align left
center Align centre
right Align right
justify Justify

Lists & Indentation

Name Description
ul Unordered list
ol Ordered list
indent Increase indent
outdent Decrease indent

Block / Typography

Name Description
paragraph Paragraph / Headings (H1–H6)
font Font family
fontsize Font size
brush Text colour & background colour
classSpan Apply CSS class to selection

Insert

Name Description
link Insert / edit hyperlink
image Insert image
video Insert video (embed)
file Insert file link
table Insert table
hr Horizontal rule
symbols Special characters

Clipboard & History

Name Description
undo Undo
redo Redo
cut Cut
copy Copy
paste Paste
selectall Select all

View / Utility

Name Description
source Toggle HTML source view
fullsize Toggle fullscreen
preview Live preview
print Print
find Find & replace
spellcheck Spell check
speech Speech recognition

Separators

Name Description
| Vertical separator bar
\n Line break (start a new toolbar row)

Example — compact toolbar:

'buttons' => [
    'bold', 'italic', 'underline', 'strikethrough', 'eraser', '|',
    'ul', 'ol', '|',
    'paragraph', 'brush', '|',
    'link', 'image', '|',
    'undo', 'redo',
],

File Manager Backends

The file_manager.backend config key controls which file manager is wired up when file-browser="true" (the default).

builtin (default)

Uses the package's own connector controller. No extra packages required.

// config/jodit.php
'file_manager' => [
    'backend' => 'builtin',
],

unisharp — UniSharp Laravel FileManager

Requires unisharp/laravel-filemanager to be installed and its routes published.

composer require unisharp/laravel-filemanager
php artisan vendor:publish --tag=lfm_public
// config/jodit.php
'file_manager' => [
    'backend' => 'unisharp',

    'unisharp' => [
        'browse_url'  => '/laravel-filemanager',
        'upload_url'  => '/laravel-filemanager/upload',
        'type'        => 'Images',   // 'Images' | 'Files'
        'window_size' => '900x600',
    ],
],

When this backend is active, a File Manager toolbar button replaces Jodit's native file browser. Clicking it opens the LFM popup; selecting a file inserts it into the editor automatically.

custom

Point the editor at any server-side connector that speaks Jodit's filebrowser protocol. Pass the URL via the component's connector-url prop, or set route.name in the config:

<x-jodit::editor
    name="content"
    connector-url="{{ route('my.connector') }}"
/>

License

MIT