amjadiqbal / blockcraft-plugin
The modern TipTap block editor & document builder for October CMS.
Package info
github.com/amjadiqbal/oc-blockcraft-plugin
Type:october-plugin
pkg:composer/amjadiqbal/blockcraft-plugin
Requires
- php: >=8.2
- composer/installers: ^1.0 || ^2.0
- october/rain: >=4.2
Requires (Dev)
- phpunit/phpunit: ^10.0 || ^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-10-12 14:58:48 UTC
README
BlockCraft
A FormWidget (blockcraft) that replaces October's native Froala
richeditor with a Vue 3 + TipTap block editor -
clean HTML or structured JSON output, native Media Manager integration, and
stable behavior inside nested Tailor/FormController repeaters.
Why
October's built-in rich text editor ships a pinned, several-major-versions- old Froala build, has limited toolbar customization, and has documented breakage when combined with Tailor repeater fields. BlockCraft is a drop-in-shaped alternative: a real Vue 3 SFC built on TipTap's ProseMirror foundation, with server-side sanitization independent of anything configured in the browser.
Features
- Headings, bold/italic/strike, inline code, lists, blockquotes, code blocks, links and horizontal rules.
- Tables you can edit: add and delete rows and columns, toggle the header row, merge and split cells, delete the table, and resize columns. The controls appear while the cursor is in a table.
- Images from October's Media Manager, editable after inserting: alt text, width, alignment, replace and remove.
- HTML source mode for editing the raw markup, still sanitized on save.
- Clean HTML or structured TipTap JSON output, sanitized server-side.
- Works inside Tailor/FormController repeaters, including rows added after the page loaded.
Requirements
- October CMS 4.2+ (needs the Vue 3 / native ESM backend)
- PHP 8.2+
Installation
composer require amjadiqbal/blockcraft-plugin
(Composer package name ends in -plugin per October's own naming
convention; it still installs at plugins/amjadiqbal/blockcraft.)
No build step is needed - the compiled editor ships in assets/dist/. If you
upload the plugin manually (FTP, zip), make sure that folder comes with it.
Usage
# fields.yaml body: label: Body type: blockcraft outputFormat: html # or 'json' for a structured TipTap document height: 400px
Options
| Option | Type | Default | Description |
|---|---|---|---|
outputFormat |
html | json |
html |
Persisted shape of the field's value. |
height |
string | 400px |
CSS height of the editor's content area. |
buttons |
array | null | null (full default toolbar) |
Restrict visible toolbar buttons: bold, italic, strike, code, heading1..heading6, bulletList, orderedList, blockquote, codeBlock, link, image, table, horizontalRule, undo, redo, source. The table and image bars appear on their own and need no entry. |
readOnly |
bool | false |
Renders the content non-editable. |
outputFormat: json stores TipTap's own document schema
({type: 'doc', content: [...]}) rather than an HTML string - useful when
your frontend wants to render content itself instead of trusting stored
markup, or when you want a stable structure for programmatic transforms.
Media Manager
Clicking the toolbar's Image button launches October's real, built-in Media
Manager (oc.mediaManager.popup) when the current backend user has
media.library access - no extra setup needed, no custom AJAX handler on
BlockCraft's side. Without that access, the Image button asks for a URL.
Editing tables and images
Put the cursor in a table and a Table bar appears under the toolbar: add a row above/below, delete a row, add a column left/right, delete a column, toggle the header row, merge cells (drag across cells to select them first), split a merged cell, and delete the table. Drag a column border to resize it.
Click an image and an Image bar appears: alt text, width in pixels, align left/center/right, replace it (through the Media Manager), and remove it.
HTML source mode
The HTML toolbar button shows the field's content as HTML, one block per
line, for editing by hand. Changes apply as you type and when you switch
back. Only HTML the editor supports is kept: unknown tags are unwrapped, and
scripts, styles, event attributes, iframes and javascript: links are
removed - in the browser, and again on the server when the form is saved
(see Sanitization). To hide the button, leave source out of buttons.
Sanitization
Both output modes are sanitized server-side, independent of anything the browser sent - including HTML typed in source mode:
htmlmode:classes/HtmlSanitizer.phpstrips any tag/attribute outside an explicit allow-list (matching BlockCraft's own extension set - nothing the editor can't already produce), stripsjavascript:/data:URIs, and forcesrel="noopener noreferrer"ontarget="_blank"links.jsonmode:classes/JsonSanitizer.phpvalidates the decoded value is a well-formed TipTap document and recursively drops any node/mark type or attribute key outside that same allow-list.
Malformed input in either mode degrades to a safe empty value - it never throws and never reaches the database unsanitized.
Repeater lifecycle
BlockCraft's ESM hydrator (assets/js/blockcraft.ts) re-scans the DOM for
new mount points on every completed backend AJAX request (ajax:done), so
a BlockCraft field added dynamically inside a repeater row - via October's
native "Add Item" action - gets its editor initialized correctly, not just
one present when the page first loaded.
It also watches for its mount elements being removed from the DOM (a
Tailor/FormController repeater row deleted) and destroys the corresponding
TipTap/Vue instance via a MutationObserver - this prevents the memory
leaks and detached event listeners a naive integration would accumulate as
rows are added and removed.
Development
npm install
npm run dev # Vite dev server with HMR
npm run build # production bundle -> assets/dist/
npm run typecheck
npm test # Vitest, mounts the real TipTap editor under jsdom
Testing
The PHPUnit suite (tests/) needs October's own base classes
(PluginTestCase, Backend\Classes\FormField/FormWidgetBase) to mean
anything, so it must run from inside a real October CMS application with
this plugin installed under plugins/amjadiqbal/blockcraft:
composer create-project october/october octoberapp
rsync -a --exclude=node_modules --exclude=assets/dist --exclude=.git \
./ octoberapp/plugins/amjadiqbal/blockcraft/
cd octoberapp
php artisan october:migrate
vendor/bin/phpunit --configuration path/to/phpunit.blockcraft.xml
scripts/ci-local.sh does all of this for you, the same way
.github/workflows/tests.yml does: a fresh October install, the plugin
installed from git archive HEAD (exactly what Packagist ships), PHPUnit,
plus the TypeScript/Vite job and a check that the committed assets/dist/
matches a fresh build. It tests the last commit, so commit first.
scripts/ci-local.sh # both jobs
JOB=phpunit PHP=php8.2 scripts/ci-local.sh
License
MIT - see LICENSE.md.
Support
- 🐛 Bug or feature request — open an issue
- 💬 Questions — contact me on Discord
- 🔒 Security issue — please report privately via GitHub's security tab
Need this customised, or something built?
I'm available for custom development, package integration, and technical consulting.
More packages
Part of a family of open-source packages — see all of them.
| oc-vueforge-plugin | The rapid Vue 3 component & widget engine for October CMS |
| laravel-tiptap | Tiptap editor for Laravel, backend-driven config and secure uploads |
| kiln | Deploy-time OPcache control for Laravel |
| laravel-logpulse | Log health monitoring & intelligent alerting for Laravel |



