A comprehensive CKEditor 5 integration for Vaadin 24+.
- 70+ Free Plugins - All plugins from the official
ckeditor5npm package - Premium Plugin Support - Easy integration with
ckeditor5-premium-features - Multiple Editor Types - Classic, Inline, Balloon, and Decoupled editors
- Theme Integration - Auto-sync with Vaadin's Lumo theme (light/dark)
- Custom Toolbar Styling - Fine-grained control over toolbar and button appearance
- File Upload Handling - Built-in upload with validation and progress tracking
- Error Handling - Comprehensive error events and fallback modes
- HTML Sanitization - Built-in sanitization policies for security
- Autosave - Debounced autosave with configurable intervals
- i18n Support - 10+ languages included
- TypeScript - Fully typed frontend component
- User Guide - Comprehensive documentation with all features
- Quick Reference - Cheat sheet for common tasks
<dependency>
<groupId>com.wontlost</groupId>
<artifactId>ckeditor-vaadin</artifactId>
<version>5.3.1</version>
</dependency>implementation("com.wontlost:ckeditor-vaadin:5.3.1")| 依赖 | 版本 | 备注 |
|---|---|---|
| Vaadin Platform | 25.2.0+ | 25.x 系列 |
CKEditor 5 (ckeditor5) |
48.2.0 | npm 精确版本 |
ckeditor5-premium-features |
48.2.0 | 与 ckeditor5 必须同版本 |
| Java | 21+ | Vaadin 25 baseline |
Jackson (tools.jackson.core) |
3.1.3+ | 由消费端提供 |
| Jakarta Servlet API | 6.1.0+ | Vaadin 25.2 支持矩阵 |
| Spring Boot | 4.0.4+ | 推荐(匹配 Jackson 3.1) |
Unreleased 版本将 CKEditor 47 → 48 的配置兼容层下沉到前端 normalizer;旧顶层
initialData/placeholder/label与 v47 AI 配置自动迁移到 v48 字段。详见 CHANGELOG。
// Using preset
VaadinCKEditor editor = VaadinCKEditor.withPreset(CKEditorPreset.STANDARD);
// With builder
VaadinCKEditor editor = VaadinCKEditor.create()
.withPreset(CKEditorPreset.FULL)
.withValue("<p>Hello World!</p>")
.build();
add(editor);| Preset | Description | Estimated Size |
|---|---|---|
EMPTY |
Minimal - only essentials | ~100KB |
BASIC |
Simple formatting (Bold, Italic, Lists, Links) | ~300KB |
STANDARD |
Common features (+ Headings, Images, Tables) | ~600KB |
FULL |
All formatting features | ~700KB |
DOCUMENT |
Professional document editing | ~800KB |
EMAIL |
Email composition with image upload | ~500KB |
NOTION |
Notion-style block editing | ~900KB |
VaadinCKEditor editor = VaadinCKEditor.create()
.withPlugins(
CKEditorPlugin.ESSENTIALS,
CKEditorPlugin.PARAGRAPH,
CKEditorPlugin.BOLD,
CKEditorPlugin.ITALIC,
CKEditorPlugin.HEADING,
CKEditorPlugin.LINK,
CKEditorPlugin.IMAGE,
CKEditorPlugin.TABLE
)
.withToolbar("heading", "|", "bold", "italic", "|", "link", "insertImage", "insertTable")
.build();// Classic (default)
VaadinCKEditor classic = VaadinCKEditor.create()
.withType(CKEditorType.CLASSIC)
.build();
// Inline - toolbar appears on selection
VaadinCKEditor inline = VaadinCKEditor.create()
.withType(CKEditorType.INLINE)
.build();
// Balloon - floating toolbar
VaadinCKEditor balloon = VaadinCKEditor.create()
.withType(CKEditorType.BALLOON)
.build();
// Decoupled - separate toolbar, supports minimap
VaadinCKEditor decoupled = VaadinCKEditor.create()
.withType(CKEditorType.DECOUPLED)
.build();// Auto (default) - syncs with Vaadin's Lumo theme
VaadinCKEditor editor = VaadinCKEditor.create()
.withTheme(CKEditorTheme.AUTO)
.build();
// Force dark theme
VaadinCKEditor darkEditor = VaadinCKEditor.create()
.withTheme(CKEditorTheme.DARK)
.build();VaadinCKEditor editor = VaadinCKEditor.create()
.withPreset(CKEditorPreset.STANDARD)
.withAutosave(content -> {
// Save content to database
saveToDatabase(content);
}, 3000) // 3 second debounce
.build();VaadinCKEditor editor = VaadinCKEditor.create()
.withPreset(CKEditorPreset.STANDARD)
.readOnly(true)
.build();
// Toggle at runtime
editor.setReadOnly(false);Premium features require a CKEditor license. Get yours at ckeditor.com/pricing.
Option A: Use VaadinCKEditorPremium class (Recommended)
Simply call VaadinCKEditorPremium.enable() once at application startup to automatically install the premium npm package:
import com.wontlost.ckeditor.VaadinCKEditorPremium;
@SpringBootApplication
public class Application implements AppShellConfigurator {
public static void main(String[] args) {
VaadinCKEditorPremium.enable(); // Enable premium features
SpringApplication.run(Application.class, args);
}
}Option B: Manual npm installation
In your Vaadin project's frontend directory:
npm install ckeditor5-premium-features🔐 Security Note: CKEditor 5 license keys are designed to be used in frontend code. To protect your license key from unauthorized use, configure Approved Hosts Whitelisting in the CKEditor Customer Portal:
- Exact domains:
example.com- Wildcard subdomains:
*.example.com- IP addresses/ranges:
192.168.*.*This ensures your license key only works on your approved domains.
// Recommended: Use environment variable to avoid committing keys to version control
String licenseKey = System.getenv("CKEDITOR_LICENSE_KEY");
VaadinCKEditor editor = VaadinCKEditor.create()
.withPreset(CKEditorPreset.STANDARD)
.withLicenseKey(licenseKey)
.addCustomPlugin(CustomPlugin.fromPremium("ExportPdf"))
.addCustomPlugin(CustomPlugin.fromPremium("ExportWord"))
.addCustomPlugin(CustomPlugin.fromPremium("ImportWord"))
.withToolbar("heading", "|", "bold", "italic", "|", "exportPdf", "exportWord")
.build();| Plugin | Description | Toolbar Item |
|---|---|---|
ExportPdf |
Export to PDF | exportPdf |
ExportWord |
Export to Word | exportWord |
ImportWord |
Import from Word | importWord |
FormatPainter |
Copy formatting | formatPainter |
SlashCommand |
Slash commands | - |
TableOfContents |
Table of contents | tableOfContents |
DocumentOutline |
Document outline | - |
Template |
Content templates | insertTemplate |
CaseChange |
Change text case | caseChange |
MergeFields |
Mail merge fields | mergeFields |
Pagination |
Page breaks | pageBreak |
AIAssistant |
AI writing assistant | aiAssistant |
AIChat |
AI chat sidebar | toggleAi |
AIQuickActions |
AI quick actions | aiQuickActions |
AIEditorIntegration |
AI editor integration | - |
AIReviewMode |
AI review mode | - |
AITranslate |
AI translation | - |
VaadinCKEditor editor = VaadinCKEditor.create()
.withPreset(CKEditorPreset.STANDARD)
.withLicenseKey("your-license-key")
.addCustomPlugin(CustomPlugin.fromPremium("Comments"))
.addCustomPlugin(CustomPlugin.fromPremium("TrackChanges"))
.addCustomPlugin(CustomPlugin.fromPremium("RevisionHistory"))
.build();CustomPlugin myPlugin = CustomPlugin.builder("MyPlugin")
.withImportPath("my-ckeditor-plugin")
.withToolbarItems("myButton")
.build();
VaadinCKEditor editor = VaadinCKEditor.create()
.withPreset(CKEditorPreset.STANDARD)
.addCustomPlugin(myPlugin)
.build();// First: npm install @example/ckeditor-plugin
CustomPlugin examplePlugin = CustomPlugin.builder("ExampleFeature")
.withImportPath("@example/ckeditor-plugin")
.withToolbarItems("exampleButton")
.build();CKEditorConfig config = new CKEditorConfig()
.withHeading(new String[]{"paragraph", "heading1", "heading2", "heading3"})
.withFontSizes(new String[]{"tiny", "small", "default", "big", "huge"})
.withFontFamilies(new String[]{"Arial", "Georgia", "Times New Roman"})
.withImageUploadUrl("/api/upload")
.withCustomConfig("placeholder", "Start typing...");
VaadinCKEditor editor = VaadinCKEditor.create()
.withPreset(CKEditorPreset.FULL)
.withConfig(config)
.build();Enable to preserve all HTML attributes:
editor.setGhsEnabled(true);VaadinCKEditor editor = VaadinCKEditor.create()
.withType(CKEditorType.DECOUPLED)
.withPreset(CKEditorPreset.FULL)
.build();
editor.setMinimapEnabled(true);Customize the toolbar appearance with fine-grained control over colors and styles. Supports multi-instance isolation - each editor can have its own unique styling.
CKEditorConfig config = new CKEditorConfig()
.setToolbarStyle(ToolbarStyle.builder()
// Toolbar container
.background("#f8f9fa")
.borderColor("#dee2e6")
.borderRadius("8px")
// Button states
.buttonBackground("transparent")
.buttonHoverBackground("rgba(0, 0, 0, 0.05)")
.buttonActiveBackground("rgba(0, 0, 0, 0.1)")
.buttonOnBackground("#e3f2fd")
.buttonOnColor("#1976d2")
// Icon color
.iconColor("#495057")
.build());
VaadinCKEditor editor = VaadinCKEditor.create()
.withPreset(CKEditorPreset.STANDARD)
.withConfig(config)
.build();Apply custom styles to individual toolbar buttons:
CKEditorConfig config = new CKEditorConfig()
.setToolbarStyle(ToolbarStyle.builder()
.background("#ffffff")
// Highlight the Bold button
.buttonStyle("Bold", ButtonStyle.builder()
.background("#fff3e0")
.hoverBackground("#ffe0b2")
.iconColor("#e65100")
.build())
// Highlight the Italic button
.buttonStyle("Italic", ButtonStyle.builder()
.background("#e3f2fd")
.hoverBackground("#bbdefb")
.iconColor("#1565c0")
.build())
.build());ToolbarStyle:
| Property | Description |
|---|---|
background |
Toolbar background color |
borderColor |
Toolbar border color |
borderRadius |
Toolbar border radius (e.g., "8px") |
buttonBackground |
Default button background |
buttonHoverBackground |
Button hover state background |
buttonActiveBackground |
Button active/pressed state background |
buttonOnBackground |
Button "on" state background (e.g., Bold when active) |
buttonOnColor |
Button "on" state text/icon color |
iconColor |
Default icon color |
ButtonStyle (for individual buttons):
| Property | Description |
|---|---|
background |
Button background color |
hoverBackground |
Hover state background |
activeBackground |
Active/pressed state background |
iconColor |
Icon color |
// Get content
String html = editor.getValue();
// Set content
editor.setValue("<p>New content</p>");
// Listen for changes
editor.addValueChangeListener(event -> {
String newValue = event.getValue();
});// Read-only
editor.setReadOnly(true);
boolean isReadOnly = editor.isReadOnly();
// Focus
editor.focus();The addon automatically resolves plugin dependencies:
// AUTO_RESOLVE (default) - adds missing dependencies
VaadinCKEditor editor = VaadinCKEditor.create()
.addPlugin(CKEditorPlugin.IMAGE_CAPTION) // IMAGE added automatically
.build();
// STRICT - fails if dependencies missing
VaadinCKEditor editor = VaadinCKEditor.create()
.addPlugin(CKEditorPlugin.IMAGE_CAPTION)
.withDependencyMode(DependencyMode.STRICT)
.build(); // Throws exception
// MANUAL - no checking
VaadinCKEditor editor = VaadinCKEditor.create()
.withPlugins(CKEditorPlugin.ESSENTIALS, CKEditorPlugin.BOLD)
.withDependencyMode(DependencyMode.MANUAL)
.build();An optional ckeditor-vaadin-testbench module provides VaadinCKEditorElement, a
type-safe Vaadin TestBench page object for the vaadin-ckeditor component.
⚠️ Vaadin TestBench is a commercial (Premium) feature. The module depends on TestBench withprovidedscope and does not bundle it; you need your own TestBench license to run tests. The core addon has no TestBench dependency.
<dependency>
<groupId>com.wontlost</groupId>
<artifactId>ckeditor-vaadin-testbench</artifactId>
<version>5.3.1</version>
<scope>test</scope>
</dependency>VaadinCKEditorElement editor = $(VaadinCKEditorElement.class).first();
editor.setData("<p>Hello</p>");
assertEquals("<p>Hello</p>", editor.getData());See ckeditor-vaadin-testbench/README.md for the
full API and setup.
- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)
- Issues: GitHub Issues
- CKEditor Docs: ckeditor.com/docs
- Vaadin: vaadin.com
Need help integrating CKEditor premium features? We offer:
- Setup & Configuration - Premium plugin integration
- Custom Development - Bespoke editor features
- Training - Team onboarding sessions
- Support Plans - Priority issue resolution
Contact: [service@wontlost.com]
For comprehensive documentation including all configuration options, events, and API details, see:
- User Guide - Full documentation
- Quick Reference - Cheat sheet
- Changelog - Version history
- Contributing - How to contribute
This addon is licensed under Apache 2.0.
CKEditor 5 is dual-licensed:
- GPL 2+ for open-source projects
- Commercial license for proprietary use
Premium features require a commercial license from CKEditor.