manogi/nova-tiptap
A Tiptap-based rich text editor field for Laravel Nova, giving you a clean, customizable WYSIWYG experience with configurable extensions and JSON/HTML output for your resource forms.
Step 0 — decide you're forking, not installing. The repo is archived (last release 2024-06-27), zero dependents, health score 1.64. You are not consuming a dependency; you are adopting source. Budget the fork before your first composer require.
composer.json constraint against your Nova version, then confirm the compiled component in dist/ was built against the Vue version Nova ships.manogi/nova-tiptap, add a VCS repository pointing at your fork and pin an exact tag:
{
"repositories": [{ "type": "vcs", "url": "[email protected]:yourorg/nova-tiptap.git" }],
"require": { "manogi/nova-tiptap": "3.2.6" }
}
Run php artisan vendor:publish if it ships publishable assets.use Manogi\Tiptap\Tiptap;
public function fields(Request $request)
{
return [
Tiptap::make('Content')
->buttons(['bold', 'italic', 'link', '|', 'heading', 'bulletList', 'codeBlock'])
->rules('nullable'),
];
}
->buttons([...]) token list and options; then src/Tiptap.php for component(), resolve(), fill(), and the meta methods; then resources/js / dist for the Vue component. Because it's archived, the source is the documentation for every edge case.Pages or Posts resource where authors need headings, lists, links, and code blocks. The exit criteria for your spike: the editor renders, saves, and reloads a real document, and you know exactly what lands in the database column (ProseMirror JSON vs HTML — verify empirically, don't trust the README).If the Nova version isn't in the supported range, stop. Porting an unmaintained field is not a spike, it's a project.
'|' separators. A short "Bio" gets ['bold', 'italic', 'link']. This is the lever you touch weekly — build a small helper so each resource declares its own toolbar.protected $casts = ['content' => 'array'];
One renderer, shared by preview, API, and email — a server-side JSON→HTML converter — so schema drift can't creep in between environments.->displayUsing() running the same JSON→HTML path, then Str::limit(strip_tags($html), 120). This is the single most common integration point and the most common place a reviewer catches you.nullable|json with a custom rule that walks the doc for required node types ("must contain at least one paragraph"). Tiptap will happily submit a structurally empty doc.->onlyOnForms() where the editor shouldn't appear on detail, and render a formatted read-only view instead. Better authoring UX, less confusion.{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"..."}]}]}), not plain strings, or round-trip tests lie.mews/purifier / HTMLPurifier) before persist and before render. The package will not do this for you and client-side sanitization does not count.FORK.md with provenance, pinned versions, compatibility matrix, custom nodes, and the fallback path (native Nova field + small custom Vue component). Add it to the Nova upgrade checklist.{"type":"doc","content":[{"type":"paragraph"}]} instead of null. Normalize before saving or you'll get non-null "empty" records that break nullable assumptions and downstream if ($post->content) checks.component() name matches the compiled component, (3) field meta is serialized via withMeta()/meta(), (4) CSP. Nearly every "broken field" report is one of those four.->buttons() and meta are supported. Anything deeper means editing the Vue source — budget that as recurring cost at each Nova upgrade.FORK.md rather than reverse-engineering them.How can I help you explore Laravel packages today?