Install the Bundle:
composer require besmartand-pro/tiptap-editor
php bin/console besmartand-pro:tiptap-editor:install
This auto-detects and installs frontend dependencies (@tiptap/*, bootstrap-icons) and scaffolds config/routes/assets.
Refresh Frontend Dependencies:
pnpm install # or npm/yarn
Use in a Symfony Form:
use BeSmartAndPro\TiptapEditorBundle\Form\Type\TiptapType;
$builder->add('content', TiptapType::class, [
'tiptap_placeholder' => 'Write here...',
]);
Test the Editor:
TiptapType field. The editor should render with a compact toolbar (bold, italic, link, etc.) and hover tooltips.Replace a plain textarea in a blog post form with the Tiptap editor:
// src/Form/BlogPostType.php
use BeSmartAndPro\TiptapEditorBundle\Form\Type\TiptapType;
$builder->add('body', TiptapType::class, [
'tiptap_placeholder' => 'Type your blog post...',
'tiptap_toolbar' => [
'bold', 'italic', 'link', 'bulletList', 'orderedList',
], // Customize toolbar buttons
]);
Result: A rich-text editor with minimal setup, ready for content creation.
Default Usage:
$builder->add('description', TiptapType::class);
Renders a preconfigured editor with default extensions (bold, italic, links, lists, etc.).
Customization:
$builder->add('content', TiptapType::class, [
'tiptap_placeholder' => 'Custom placeholder',
'tiptap_toolbar' => ['bold', 'italic', 'strike'], // Limit buttons
'tiptap_extensions' => ['link', 'image'], // Enable/disable extensions
]);
Validation:
Use Symfony’s built-in validation (e.g., @Assert\Length) on the form field. Tiptap outputs HTML, so validate accordingly:
$builder->add('content', TiptapType::class, [
'constraints' => [
new Length(['max' => 5000]),
],
]);
Basic Field:
yield TiptapField::new('content', 'Content')->setPlaceholder('Edit here...');
Automatically integrates into EasyAdmin’s CRUD interface.
Configuration:
yield TiptapField::new('body', 'Post Body')
->setPlaceholder('Write your post...')
->setToolbar(['bold', 'link', 'image']);
# config/packages/besmartand_pro_tiptap_editor.yaml
besmartand_pro_tiptap_editor:
upload:
enabled: true
filesystem_service: 'oneup_flysystem.images_filesystem'
public_url_prefix: '/uploads'
max_file_size: 5MB
enabled: true).besmartand_pro/tiptap_editor_controller.ts). Override it in assets/controllers/besmartand_pro/tiptap_editor_controller.ts:
import { Controller } from '@hotwired/stimulus';
import { TiptapEditor } from 'besmartand-pro/tiptap-editor';
export default class extends Controller {
static values = { ...TiptapEditor.values };
connect() {
this.editor = new TiptapEditor(this);
// Custom logic (e.g., auto-formatting)
}
}
Render Raw HTML:
Use Twig’s |raw filter to display Tiptap’s HTML output:
{{ form_row(post.body) }}
<div class="post-content">
{{ post.body|raw }}
</div>
Custom Styling:
Override the bundle’s SCSS in assets/styles/besmartand_pro_tiptap_editor.scss:
.tiptap-editor {
border: 1px solid #ccc;
border-radius: 4px;
}
Frontend Build Tools:
webpack.config.js includes:
Encore
.addEntry('tiptap', './assets/styles/besmartand_pro_tiptap_editor.scss')
.enableSassLoader();
vite.config.ts:
import { defineConfig } from 'vite';
export default defineConfig({
css: {
preprocessorOptions: {
scss: { additionalData: '@import "./assets/styles/besmartand_pro_tiptap_editor.scss";' },
},
},
});
Backend Handling:
TEXT (HTML) or JSON (serialized editor state). Example Doctrine entity:
/**
* @ORM\Column(type="text")
*/
private $content;
HTMLPurifier:
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
$sanitized = (new HTMLPurifier())->purify($rawHtml);
Performance:
strike, underline) to reduce bundle size.max_file_size and resize images server-side (e.g., with league/glide).Testing:
public function testTiptapFormSubmission()
{
$form = $this->factory->create(TiptapType::class);
$form->submit(['content' => '<p>Hello <strong>World</strong></p>']);
$this->assertTrue($form->isValid());
}
Frontend Dependencies:
package.json lacks @tiptap/* or bootstrap-icons. Manually add them if auto-installation skips:
pnpm add @tiptap/core @tiptap/starter-kit @tiptap/extension-image bootstrap-icons
@import "~bootstrap-icons/font/bootstrap-icons.css";
@import "./assets/styles/besmartand_pro_tiptap_editor.scss";
Stimulus Conflicts:
besmartand-pro--tiptap-editor. Avoid naming custom Stimulus controllers similarly.assets/controllers is scanned in your Stimulus bootstrap (e.g., stimulus_controller.js):
import { application } from 'stimulus';
const controllerFiles = require.context('./controllers', true, /\.js$/);
controllerFiles.keys().forEach(key => application.register(key.replace(/(\.\/|\.js)/g, '')));
Image Uploads:
filesystem_service (e.g., oneup_flysystem.images_filesystem) exists and is writable.security_attribute (e.g., ROLE_ADMIN) restricts uploads. Test with:
besmartand_pro_tiptap_editor:
upload:
security_attribute: IS_AUTHENTICATED_FULLY
public_url_prefix must match your asset server (e.g., /cdn for Cloudflare).EasyAdmin Quirks:
->setFormTypeOption() to tweak:How can I help you explore Laravel packages today?