PHPackages                             ptnghia/laravel-tiptap-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. ptnghia/laravel-tiptap-editor

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

ptnghia/laravel-tiptap-editor
=============================

A Laravel package providing a Tiptap-based rich text editor with Bootstrap 5 layout, media management, and AI content generation

v1.3.0(2mo ago)03MITJavaScriptPHP ^8.2

Since Feb 27Pushed 2mo agoCompare

[ Source](https://github.com/ptnghia/laravel-tiptap-editor)[ Packagist](https://packagist.org/packages/ptnghia/laravel-tiptap-editor)[ RSS](/packages/ptnghia-laravel-tiptap-editor/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (10)Versions (5)Used By (0)

Laravel Tiptap Editor
=====================

[](#laravel-tiptap-editor)

[![PHP](https://camo.githubusercontent.com/187240af044d09d5b14a1d9d9ebdf3f7a993e4c7bc09bdb46b4ba661a891bf5b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e322532422d626c7565)](https://php.net)[![Laravel](https://camo.githubusercontent.com/391257e76c9420905a4f88825c9d116b09f985aa5eb286e2b062372cd66031f1/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d313125323025374325323031322d726564)](https://laravel.com)[![License: MIT](https://camo.githubusercontent.com/5caa455d8debc46fb23abbadb45a733a937f3910a73fc875c2f7820468e1bb54/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d677265656e)](LICENSE)[![Tests](https://camo.githubusercontent.com/163a6a112f91f4f67acbf0ec8c988cf3c339569532f5a3cba7b78fcf495a79dc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f74657374732d32313425323070617373696e672d627269676874677265656e)](tests/)[![Version](https://camo.githubusercontent.com/b797198bc0a5fcb2779537ade6b0dbab82a9efd3d9158d0b4e5dc9f5a5a55691/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f76657273696f6e2d76312e332e302d626c7565)](CHANGELOG.md)

A full-featured **Laravel package** providing a rich text editor built on **[Tiptap v2](https://tiptap.dev)**, **Bootstrap 5** (or **Tailwind CSS**), with media management, server-side rendering, and optional AI content generation. Works with standard Laravel + Blade — no SPA required.

---

✨ Features
----------

[](#-features)

- **Rich Text** — Bold, italic, underline, strikethrough, subscript, superscript, text color, highlight
- **Headings &amp; Structure** — H1–H4, paragraph, horizontal rule, hard break
- **Lists** — Bullet list, ordered list (with start offset)
- **Bootstrap 5 Layout** — Row/column grid with responsive breakpoints (`col-md-6`, `col-lg-4`, etc.)
- **Bootstrap Components** — Alert (8 types), Card (header/body/footer), Button (inline atom)
- **Media** — Image upload with thumbnail generation, Video embed (YouTube, Vimeo, MP4), **Media library** for reusing uploaded files
- **Gallery** — Multi-image gallery with responsive grid and lightbox
- **Table** — Full table editing, cell merge (colspan/rowspan), Bootstrap-styled
- **Code Block** — Syntax highlighting via lowlight
- **Links** — Internal/external links with `rel`/`target` configuration
- **Slash Commands** — Notion-style `/` command palette for quick block insertion
- **Block Menu** — Floating action menu: duplicate, move up/down, delete, transform block
- **Content Safety** — JSON sanitization, URL whitelist, XSS prevention, depth/size limits, file content scanning, SVG sanitization
- **Upload Security** — Gate/role-based permissions, blocked extensions, MIME mismatch detection, double-extension prevention, anti-polyglot scanning
- **Server-side Rendering** — JSON → clean HTML via Blade partials; supports **Bootstrap 5** or **Tailwind CSS** output theme
- **Dark Mode** — Auto (system), light, dark via CSS variables
- **Keyboard Shortcuts** — Built-in `Ctrl+/` help modal with all shortcuts listed
- **Accessibility** — WCAG 2.1 AA: ARIA roles, roving tabindex, live region announcements
- **Responsive Preview** — Desktop / Tablet (768px) / Mobile (375px) preview inside editor
- **AI Content Generation** *(optional)* — OpenAI &amp; Claude: generate, refine, summarize, translate
- **i18n** — English &amp; Vietnamese included; fully translatable

---

Requirements
------------

[](#requirements)

DependencyVersionPHP8.2+Laravel11.x or 12.x> Pre-built JS/CSS assets are included in `dist/` — no Node.js required for production use.

---

Installation
------------

[](#installation)

### 1. Install via Composer

[](#1-install-via-composer)

```
composer require ptnghia/laravel-tiptap-editor
```

The service provider and facade are auto-discovered.

### 2. Publish Assets

[](#2-publish-assets)

```
# JS + CSS assets → public/vendor/tiptap-editor/
php artisan vendor:publish --tag=tiptap-editor-assets

# Config file → config/tiptap-editor.php
php artisan vendor:publish --tag=tiptap-editor-config

# Database migrations (tiptap_media table)
php artisan vendor:publish --tag=tiptap-editor-migrations
php artisan migrate
```

Optional:

```
# Blade views (for customizing rendered HTML)
php artisan vendor:publish --tag=tiptap-editor-views

# Language files
php artisan vendor:publish --tag=tiptap-editor-lang
```

### 3. Include Assets in Your Layout

[](#3-include-assets-in-your-layout)

```

    ...

```

---

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

[](#basic-usage)

### Blade Component

[](#blade-component)

```

    @csrf

    Save

```

### Component Props

[](#component-props)

PropTypeDefaultDescription`name``string``'content'`Hidden input field name`value``string|array|null``null`Initial content (Tiptap JSON array or JSON string)`config``array``[]`Override editor configuration`placeholder``string`From lang fileEditor placeholder text`disabled``bool``false`Render editor as read-only`id``string|null`Auto-generatedHTML `id` for the wrapper element### Read Submitted Content

[](#read-submitted-content)

The editor submits a JSON string via the named hidden input:

```
public function store(Request $request)
{
    $request->validate(['content' => 'required|string']);

    $post = Post::create([
        'content_json' => $request->input('content'),
    ]);
}
```

---

Server-side Rendering
---------------------

[](#server-side-rendering)

### Via Facade

[](#via-facade)

```
use Suspended\TiptapEditor\Facades\TiptapEditor;

$html = TiptapEditor::render($post->content_json);
// or pass an array directly
$html = TiptapEditor::render($post->content_array);
```

```
{!! $html !!}
```

### Via Eloquent Trait

[](#via-eloquent-trait)

```
use Suspended\TiptapEditor\Traits\HasTiptapContent;

class Post extends Model
{
    use HasTiptapContent;

    // Expects a 'content_json' column (override with $tiptapColumn)
}
```

Available methods:

```
$post->renderContent();          // JSON → safe HTML string
$post->getExcerpt(200);          // Plain-text excerpt, 200 chars
$post->getPlainText();           // All text, no markup
$post->getHeadings();            // [['level' => 1, 'text' => '...']]
$post->hasContent();             // bool
$post->getTiptapContent();       // Raw content as array
$post->setTiptapContent($json);  // Set from array or JSON string
```

---

Configuration
-------------

[](#configuration)

Publish and edit `config/tiptap-editor.php`:

### Extensions

[](#extensions)

Enable or disable individual features:

```
'extensions' => [
    // Text formatting
    'paragraph', 'heading', 'bold', 'italic', 'underline', 'strike',
    'subscript', 'superscript', 'blockquote', 'codeBlock', 'horizontalRule',
    'hardBreak', 'link', 'textAlign', 'color', 'highlight', 'characterCount',

    // Bootstrap layout & components
    'bootstrapRow', 'bootstrapCol',
    'bootstrapAlert', 'bootstrapCard', 'bootstrapButton',

    // Media
    'customImage', 'customVideo', 'gallery',

    // Table
    'table', 'tableRow', 'tableCell', 'tableHeader',

    // UX features
    'slashCommands',
],
```

### Toolbar Groups

[](#toolbar-groups)

```
'toolbar' => [
    'groups' => [
        'text'      => ['bold', 'italic', 'underline', 'strike'],
        'heading'   => ['h1', 'h2', 'h3', 'h4'],
        'alignment' => ['alignLeft', 'alignCenter', 'alignRight', 'alignJustify'],
        'list'      => ['bulletList', 'orderedList'],
        'insert'    => ['link', 'image', 'video', 'table', 'horizontalRule'],
        'block'     => ['blockquote', 'codeBlock'],
        'layout'    => ['row'],
        'component' => ['alert', 'card', 'button'],
        'format'    => ['color', 'highlight', 'subscript', 'superscript'],
        'history'   => ['undo', 'redo'],
        'utils'     => ['gallery', 'darkMode', 'shortcuts'],
    ],
],
```

Override per-instance in Blade:

```

```

### Theme

[](#theme)

```
'theme' => 'auto',  // 'auto' | 'light' | 'dark'
```

### Output Theme (Tailwind CSS)

[](#output-theme-tailwind-css)

By default the server-rendered HTML uses **Bootstrap 5** classes. Switch to Tailwind with a single config change:

```
// config/tiptap-editor.php
'rendering' => [
    'output_theme' => 'tailwind',  // 'bootstrap' (default) | 'tailwind'

    // Auto-inject a pre-built fallback stylesheet if your project
    // does not have Tailwind CSS installed/built:
    'tailwind_fallback_css' => true,

    // Override specific component classes:
    'class_overrides' => [
        'card'      => 'my-card rounded-xl shadow-lg',
        'card.body' => 'p-8',
    ],
],
```

> **Note:** `output_theme` only affects rendered **output HTML** (e.g. `TiptapEditor::render()`). The editor admin UI is unaffected.

**Tailwind purge** — Tailwind purges classes at build time. Add the safelist below to `tailwind.config.js` in your host app so dynamic content classes are not stripped:

```
safelist: [
    { pattern: /^(sm|md|lg|xl):col-span-(1[0-2]|[1-9])$/ },
    { pattern: /^col-span-(1[0-2]|[1-9])$/ },
    { pattern: /^gap-[0-5]$/ },
    { pattern: /^(bg|text|border)-(blue|red|green|yellow|gray|sky)-(50|100|200|500|600|700|800|900)$/ },
],
```

Alternatively, enable `tailwind_fallback_css` (zero-config, no Tailwind install required) — a pre-built stylesheet covering all package classes is published to `public/vendor/tiptap-editor/css/tailwind-fallback.css`.

### Media Settings

[](#media-settings)

```
'media' => [
    'disk'          => env('TIPTAP_MEDIA_DISK', 'public'),
    'path'          => 'tiptap-media',
    'max_file_size' => 5120,  // KB (5 MB)

    'allowed_types' => [
        'image/jpeg', 'image/png', 'image/gif',
        'image/webp', 'image/svg+xml',
        'video/mp4', 'video/webm',
    ],

    // Requires: composer require intervention/image
    'image_sizes' => [
        'thumbnail' => [150, 150],
        'medium'    => [600, null],   // null = auto height
        'large'     => [1200, null],
    ],

    'webp_conversion' => true,
    'webp_quality'    => 85,
    'strip_exif'      => true,

    'rate_limit' => [
        'max_uploads' => 30,
        'per_minutes' => 1,
    ],
],
```

### Upload Security &amp; Permissions

[](#upload-security--permissions)

```
'media' => [
    // Upload directory organization
    'directory_strategy' => env('TIPTAP_MEDIA_DIR_STRATEGY', 'default'),
    // 'default' — tiptap-media/YYYY/MM/
    // 'user'    — tiptap-media/user-{id}/YYYY/MM/
    // 'custom'  — use directory_resolver callback

    'directory_resolver' => null,
    // Example:  fn($basePath, $datePath, $user) => "{$basePath}/team-{$user->team_id}/{$datePath}"

    // Permission gate (Laravel Gate name, null = no gate check)
    'permissions' => [
        'gate'  => env('TIPTAP_UPLOAD_GATE', null),    // e.g. 'upload-media'
        'roles' => [],                                   // e.g. ['admin', 'editor']
        // Compatible with Spatie/Permission (hasAnyRole) or a simple 'role' attribute
    ],

    // File extensions that will always be rejected
    'blocked_extensions' => [
        'php', 'php3', 'php4', 'php5', 'php7', 'php8', 'phtml', 'phar',
        'exe', 'bat', 'cmd', 'com', 'msi', 'dll',
        'sh', 'bash', 'csh', 'ksh', 'zsh',
        'js', 'jsx', 'ts', 'tsx',
        'py', 'pyc', 'rb', 'pl', 'cgi',
        'asp', 'aspx', 'jsp', 'jspx',
        'htaccess', 'htpasswd',
        'env', 'ini', 'yml', 'yaml', 'toml',
    ],
],
```

#### Setting up Gate-based permissions

[](#setting-up-gate-based-permissions)

```
// In AuthServiceProvider or a Gate definition
Gate::define('upload-media', function ($user) {
    return $user->is_editor || $user->is_admin;
});
```

```
TIPTAP_UPLOAD_GATE=upload-media
```

#### Role-based permissions (Spatie/Permission)

[](#role-based-permissions-spatiepermission)

```
// config/tiptap-editor.php
'media' => [
    'permissions' => [
        'roles' => ['admin', 'editor', 'contributor'],
    ],
],
```

### Link &amp; Sanitization Settings

[](#link--sanitization-settings)

Control which HTML attributes are allowed in the rendered output:

```
'sanitization' => [
    'allowed_attributes' => [
        // Link attributes
        'href', 'target', 'rel', 'title',

        // Image attributes
        'src', 'alt', 'width', 'height', 'loading',

        // Layout & component attributes
        'class', 'data-type', 'data-alert-type', 'data-col-class',

        // Table attributes
        'role', 'colspan', 'rowspan',

        // Style (limited to color/background-color via the sanitizer)
        'style',
    ],
    'max_nesting_depth' => 10,
    'max_content_size'  => 512000,  // bytes (500 KB)
],
```

URL safety is always enforced:

```
✅ Allowed: http://, https://, mailto:, tel:, /relative, #anchor
❌ Blocked:  javascript:, data:, vbscript:, file:

```

External links (`target="_blank"`) automatically receive `rel="noopener noreferrer"`.

### Table Rendered Output

[](#table-rendered-output)

By default tables render as ``. After publishing views you can customise [resources/views/vendor/tiptap-editor/renders/table.blade.php](resources/views/renders/table.blade.php) to add `table-striped`, `table-hover`, etc.

### Video Providers

[](#video-providers)

```
'video_providers' => [
    'youtube' => [
        'regex'     => '/(?:youtube\.com\/(?:watch\?v=|embed\/)|youtu\.be\/)([a-zA-Z0-9_-]+)/',
        'embed_url' => 'https://www.youtube-nocookie.com/embed/{id}',
    ],
    'vimeo' => [
        'regex'     => '/vimeo\.com\/(\d+)/',
        'embed_url' => 'https://player.vimeo.com/video/{id}',
    ],
],
```

### Route Settings

[](#route-settings)

```
'routes' => [
    'prefix'     => 'tiptap-editor',
    'middleware' => ['web', 'auth'],
],
```

**Package routes:**

MethodURLName`POST``/tiptap-editor/media/upload``tiptap-editor.media.upload``GET``/tiptap-editor/media/browse``tiptap-editor.media.browse``DELETE``/tiptap-editor/media/{id}``tiptap-editor.media.delete``POST``/tiptap-editor/ai/generate``tiptap-editor.ai.generate``POST``/tiptap-editor/ai/refine``tiptap-editor.ai.refine``POST``/tiptap-editor/ai/summarize``tiptap-editor.ai.summarize``POST``/tiptap-editor/ai/translate``tiptap-editor.ai.translate`> AI routes are only registered when `ai.enabled = true`.

---

AI Content Generation (Optional)
--------------------------------

[](#ai-content-generation-optional)

### Setup

[](#setup)

```
# For OpenAI
composer require openai-php/laravel

# For Claude (uses Guzzle HTTP)
composer require guzzlehttp/guzzle
```

```
TIPTAP_AI_ENABLED=true
TIPTAP_AI_PROVIDER=openai        # openai | claude

OPENAI_API_KEY=sk-...
TIPTAP_AI_OPENAI_MODEL=gpt-4o-mini

ANTHROPIC_API_KEY=sk-ant-...
TIPTAP_AI_CLAUDE_MODEL=claude-sonnet-4-20250514
```

### Configuration

[](#configuration-1)

```
'ai' => [
    'enabled'          => env('TIPTAP_AI_ENABLED', false),
    'default_provider' => env('TIPTAP_AI_PROVIDER', 'openai'),

    'providers' => [
        'openai' => [
            'api_key'     => env('OPENAI_API_KEY'),
            'model'       => env('TIPTAP_AI_OPENAI_MODEL', 'gpt-4o-mini'),
            'max_tokens'  => 4096,
            'temperature' => 0.7,
        ],
        'claude' => [
            'api_key'    => env('ANTHROPIC_API_KEY'),
            'model'      => env('TIPTAP_AI_CLAUDE_MODEL', 'claude-sonnet-4-20250514'),
            'max_tokens' => 4096,
        ],
    ],

    'rate_limit' => [
        'max_requests' => 20,
        'per_minutes'  => 60,
    ],

    'capabilities' => [
        'generate'  => true,
        'refine'    => true,
        'summarize' => true,
        'translate' => true,
    ],
],
```

### Use in PHP

[](#use-in-php)

```
use Suspended\TiptapEditor\Services\AiContentService;

$ai = app(AiContentService::class);

$response = $ai->generate('Write a blog post about Laravel packages');
echo $response->content;     // HTML string
echo $response->tokensUsed;  // int

$refined   = $ai->refine($existingHtml, 'Make it more concise');
$summary   = $ai->summarize($longContent, maxLength: 300);
$translated = $ai->translate($content, 'vi');
```

---

Content Sanitization
--------------------

[](#content-sanitization)

```
use Suspended\TiptapEditor\Facades\TiptapEditor;

// Sanitize before storing
$cleanJson = TiptapEditor::sanitize($request->input('content'));
$post->content_json = $cleanJson;
```

The sanitizer:

- Whitelists node types, attributes, and URL schemes
- Removes `javascript:`, `data:`, `vbscript:` URLs
- Strips control characters and empty marks
- Enforces max nesting depth and total content size

---

Keyboard Shortcuts
------------------

[](#keyboard-shortcuts)

Press **Ctrl+/** (**⌘/** on Mac) to open the shortcuts help modal.

ShortcutAction`Ctrl+B`Bold`Ctrl+I`Italic`Ctrl+U`Underline`Ctrl+Shift+X`Strikethrough`Ctrl+Alt+0`Paragraph`Ctrl+Alt+1` – `4`Heading 1–4`Ctrl+Shift+8`Bullet list`Ctrl+Shift+7`Ordered list`Ctrl+Shift+B`Blockquote`Ctrl+Alt+C`Code block`Ctrl+Z`Undo`Ctrl+Shift+Z`Redo`/`Slash command menu`Ctrl+/`Shortcuts help---

Customizing Rendered HTML
-------------------------

[](#customizing-rendered-html)

After publishing views, edit the Blade partials in `resources/views/vendor/tiptap-editor/renders/`:

FileRenders`paragraph.blade.php````heading.blade.php``` – ```image.blade.php``` with optional caption`video.blade.php``` (YouTube / Vimeo) or `` (MP4)`bootstrap-row.blade.php````bootstrap-col.blade.php````alert.blade.php````card.blade.php`Bootstrap card (header / body / footer)`button.blade.php````gallery.blade.php`Responsive image grid`gallery-image.blade.php`Single gallery image`table.blade.php````list.blade.php``` / ```blockquote.blade.php````code-block.blade.php````horizontal-rule.blade.php```---

Extending
---------

[](#extending)

### Custom Node Renderer

[](#custom-node-renderer)

```
use Suspended\TiptapEditor\Support\NodeRegistry;
use Suspended\TiptapEditor\Services\HtmlRenderer;

// In a ServiceProvider boot()
$registry = app(NodeRegistry::class);

$registry->registerSchema('myBlock', [
    'allowed_attributes' => ['class', 'data-type'],
    'allowed_children'   => ['paragraph'],
]);

$registry->register('myBlock', function (array $node, HtmlRenderer $renderer): string {
    $content = $renderer->renderChildren($node);
    return "{$content}";
});
```

### Custom AI Provider

[](#custom-ai-provider)

```
use Suspended\TiptapEditor\Contracts\AiProviderInterface;
use Suspended\TiptapEditor\Services\Ai\AiResponse;

class MyProvider implements AiProviderInterface
{
    public function generate(string $prompt, array $options = []): AiResponse
    {
        $content = '...'; // call your API
        return new AiResponse(
            content: $content,
            tiptapJson: null,
            tokensUsed: 0,
            provider: 'my-provider',
            model: 'my-model',
        );
    }

    public function supports(string $capability): bool
    {
        return in_array($capability, ['generate', 'refine']);
    }

    public function getName(): string { return 'my-provider'; }
}
```

```
app(AiContentService::class)->registerProvider('my-provider', new MyProvider());
```

---

Internationalization
--------------------

[](#internationalization)

Includes `en` and `vi` translations. Publish to customise or add new locales:

```
php artisan vendor:publish --tag=tiptap-editor-lang
# lang/vendor/tiptap-editor/{locale}/editor.php
```

---

Testing
-------

[](#testing)

```
./vendor/bin/phpunit
```

**214 tests, 440 assertions** covering HTML rendering, sanitization, content validation, media, tables, AI providers, gallery, traits, config, and translations.

---

Directory Structure
-------------------

[](#directory-structure)

```
src/
├── EditorServiceProvider.php
├── Facades/TiptapEditor.php
├── Contracts/AiProviderInterface.php
├── Http/Controllers/  (MediaUploadController, AiContentController)
├── Http/Middleware/   (ValidateMediaUpload, AiRateLimiter)
├── Http/Requests/     (MediaUploadRequest, AiContentRequest)
├── Models/Media.php
├── Services/
│   ├── HtmlRenderer.php
│   ├── JsonSanitizer.php
│   ├── ContentValidator.php
│   ├── MediaManager.php
│   ├── AiContentService.php
│   └── Ai/ (OpenAiProvider, ClaudeProvider, AiResponse)
├── Support/ (NodeRegistry, AiPromptTemplates)
├── Traits/HasTiptapContent.php
└── View/Components/TiptapEditor.php

resources/js/editor/
├── index.js            Editor.js            Toolbar.js
├── extensions/         (9 Tiptap extensions)
├── MediaBrowser.js     AiPanel.js           BlockMenu.js
├── KeyboardShortcuts.js AccessibilityManager.js ResponsivePreview.js
└── utils/              (helpers.js, sanitizer.js)

dist/
├── js/tiptap-editor.es.js   (685 KB / 180 KB gzipped)
├── js/tiptap-editor.umd.js  (449 KB / 136 KB gzipped)
└── css/tiptap-editor.css    (27 KB / 5 KB gzipped)

```

---

License
-------

[](#license)

MIT License. See [LICENSE](LICENSE) for details.

---

Changelog
---------

[](#changelog)

### v1.3.0 — 2026-03-01

[](#v130--2026-03-01)

**Tailwind CSS Output Theme**

- New `ClassMapInterface` / `ClassMap` architecture — Strategy pattern for CSS framework–agnostic HTML rendering
- `BootstrapClassMap` — extracts all existing Bootstrap 5 classes (zero behavior change, fully backward compatible)
- `TailwindClassMap` — full Tailwind CSS equivalents for every component: Alert, Card, Button, Row/Col grid, Table, Image, Video, Gallery
- Automatic Bootstrap col class → Tailwind `col-span-*` / responsive `md:col-span-*` conversion
- `data-tiptap-type` / `data-tiptap-variant` attributes added to output elements when using Tailwind theme (enables CSS targeting fallback)
- New `resources/css/tailwind-fallback.css` (~13 KB) — pre-built stylesheet covering all Tailwind utility classes used in rendered output
- Auto-inject fallback CSS via `@push('styles')` in Blade component when `tailwind_fallback_css = true`
- New config keys under `rendering`: `output_theme`, `tailwind_fallback_css`, `class_overrides`
- `output_theme` env variable: `TIPTAP_OUTPUT_THEME`

**Breaking changes:** None — `output_theme` defaults to `'bootstrap'`.

### v1.1.0

[](#v110)

**Media Library**

- Browse and reuse previously uploaded images/videos from a new "Library" tab in Image and Video modals
- Searchable grid with pagination, click-to-select, and instant insert
- Integrated with existing browse API (`GET /tiptap-editor/media/browse`)

**Upload Security &amp; Permissions**

- Gate-based and role-based upload authorization (compatible with Spatie/Permission)
- Configurable upload directory strategy: `default`, `user` (per-user folders), `custom` (resolver callback)
- Blocked file extensions list (PHP, EXE, shell scripts, etc.) — prevents upload of dangerous files
- Double-extension detection (e.g., `malware.php.jpg`)
- File content scanning: detects embedded PHP tags, `eval()`, `exec()`, polyglot attack patterns
- MIME type mismatch detection (compares detected vs. declared MIME types)
- Null byte filename protection
- Filename sanitization (path traversal prevention, length limits)

**SVG Security**

- SVG file sanitization on upload: strips ``, `on*` event handlers, `javascript:` URIs, ``, external `` references

**CSS Injection Prevention**

- Color values in highlight and text style marks are now validated against safe patterns (hex, rgb/hsl, named colors)

**Other**

- TrailingNode extension (auto-appends paragraph after block nodes)
- Configurable editor height, scroll, and CSS resize handle
- Edit-after-insert for all block tools (Card, Gallery, Alert, Table)

### v1.0.0 – 2026-02-27

[](#v100--2026-02-27)

Initial release.

**Core**

- Rich text editing with 20+ formatting options
- Bootstrap 5 grid layout (Row/Column, 8 responsive presets)
- Bootstrap components: Alert, Card, Button
- Table editing (merge cells, Bootstrap styled)
- Media: image upload + thumbnail generation, video embed (YouTube/Vimeo/MP4)
- Gallery: responsive grid, lightbox
- Server-side JSON→HTML rendering via Blade partials
- Content sanitization &amp; validation (whitelist-based, XSS-safe)
- `HasTiptapContent` Eloquent trait

**UX**

- Slash commands (`/` palette, 18 commands)
- Block menu (drag handle, duplicate, delete, transform)
- Dark mode (auto/light/dark, CSS variables)
- Keyboard shortcuts help modal (`Ctrl+/`)
- WCAG 2.1 AA accessibility (ARIA, roving tabindex, live regions)
- Responsive preview (desktop / tablet / mobile)

**AI** *(optional)*

- OpenAI &amp; Claude providers (strategy pattern)
- Actions: generate, refine, summarize, translate
- Configurable rate limiting
- Built-in prompt templates

**Other**

- i18n: English &amp; Vietnamese
- 202 tests, 422 assertions

###  Health Score

38

—

LowBetter than 85% of packages

Maintenance86

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity49

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 ~0 days

Total

4

Last Release

73d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/10464619?v=4)[Matt Ryan](/maintainers/oryn)[@oryn](https://github.com/oryn)

---

Top Contributors

[![ptnghia](https://avatars.githubusercontent.com/u/23566941?v=4)](https://github.com/ptnghia "ptnghia (12 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/ptnghia-laravel-tiptap-editor/health.svg)

```
[![Health](https://phpackages.com/badges/ptnghia-laravel-tiptap-editor/health.svg)](https://phpackages.com/packages/ptnghia-laravel-tiptap-editor)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3274.9M308](/packages/psalm-plugin-laravel)[laravel/cashier

Laravel Cashier provides an expressive, fluent interface to Stripe's subscription billing services.

2.5k25.9M107](/packages/laravel-cashier)[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k12.1M99](/packages/laravel-pulse)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9682.1M97](/packages/roots-acorn)[laravel/cashier-paddle

Cashier Paddle provides an expressive, fluent interface to Paddle's subscription billing services.

264778.4k3](/packages/laravel-cashier-paddle)[dragon-code/pretty-routes

Pretty Routes for Laravel

10058.7k4](/packages/dragon-code-pretty-routes)

PHPackages © 2026

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