Caption functionality allowing users to add, edit, and toggle descriptive text below images with full editor integration.
Main caption plugin that combines editing and UI functionality.
/**
* Main caption plugin that combines editing and UI functionality
*/
class ImageCaption {
static pluginName: 'ImageCaption';
static requires: [ImageCaptionEditing, ImageCaptionUI];
static isOfficialPlugin: true;
}Usage:
import { ImageCaption } from '@ckeditor/ckeditor5-image';
import { ClassicEditor } from '@ckeditor/ckeditor5-editor-classic';
ClassicEditor
.create(document.querySelector('#editor'), {
plugins: [ImageCaption],
image: {
toolbar: ['toggleImageCaption']
}
});Core editing functionality for image captions with schema and command registration.
/**
* Core editing functionality for image captions with schema and command registration
*/
class ImageCaptionEditing {
static pluginName: 'ImageCaptionEditing';
static requires: [ImageUtils, ImageCaptionUtils];
static isOfficialPlugin: true;
}User interface for image caption functionality with toggle button.
/**
* User interface for image caption functionality with toggle button
*/
class ImageCaptionUI {
static pluginName: 'ImageCaptionUI';
static requires: [ImageCaptionEditing];
static isOfficialPlugin: true;
}Utility functions and helpers for image caption operations.
/**
* Utility functions and helpers for image caption operations
*/
class ImageCaptionUtils {
static pluginName: 'ImageCaptionUtils';
static requires: [ImageUtils];
static isOfficialPlugin: true;
/**
* Get caption element for an image
* @param imageElement - Image model element
* @returns Caption element or null
*/
getCaptionFromImageElement(imageElement: any): any | null;
/**
* Get image element that contains a caption
* @param captionElement - Caption model element
* @returns Image element or null
*/
getImageElementFromCaption(captionElement: any): any | null;
/**
* Check if image has visible caption
* @param imageElement - Image model element
* @returns True if caption is visible
*/
isImageCaptionVisible(imageElement: any): boolean;
/**
* Check if image caption element matches given element
* @param element - Element to check
* @returns True if element is image caption
*/
matchImageCaptionViewElement(element: any): any | null;
}Usage:
const captionUtils = editor.plugins.get('ImageCaptionUtils');
const imageUtils = editor.plugins.get('ImageUtils');
// Get selected image
const selection = editor.model.document.selection;
const imageElement = imageUtils.getClosestSelectedImageElement(selection);
if (imageElement) {
// Check if image has caption
const hasCaption = captionUtils.isImageCaptionVisible(imageElement);
console.log('Image has caption:', hasCaption);
// Get caption element
const captionElement = captionUtils.getCaptionFromImageElement(imageElement);
if (captionElement) {
console.log('Caption text:', captionElement.getChild(0).data);
}
}Command for toggling caption visibility on selected images.
/**
* Command for toggling caption visibility on selected images
*/
class ToggleImageCaptionCommand {
constructor(editor: Editor);
/**
* Execute caption toggle
*/
execute(): void;
/** True if selected image has visible caption */
readonly value: boolean;
/** True if command can be executed (image is selected) */
readonly isEnabled: boolean;
}Usage:
// Toggle caption on selected image
editor.execute('toggleImageCaption');
// Check if selected image has caption
const command = editor.commands.get('toggleImageCaption');
console.log('Has caption:', command.value);
console.log('Can toggle:', command.isEnabled);
// Listen for caption changes
command.on('change:value', (evt, name, value, oldValue) => {
console.log('Caption toggled:', value ? 'added' : 'removed');
});The caption functionality extends the image model with caption support:
// Model structure for image with caption
interface ImageBlockModel {
name: 'imageBlock';
children: [
{ name: 'imageInline'; attributes: { src: string; alt?: string; } },
{ name: 'caption'; children: Array<any>; } // Optional caption element
];
attributes: {
imageStyle?: string;
width?: string;
height?: string;
};
}Usage in Model:
// Check model structure
editor.model.document.on('change:data', () => {
const root = editor.model.document.getRoot();
for (const child of root.getChildren()) {
if (child.name === 'imageBlock') {
const caption = child.getChild(1);
if (caption && caption.name === 'caption') {
console.log('Image has caption:', caption.isEmpty ? 'empty' : 'with content');
}
}
}
});// View structure for image with caption
interface ImageBlockView {
name: 'figure';
classes: ['image'];
children: [
{ name: 'img'; attributes: { src: string; alt?: string; } },
{ name: 'figcaption'; } // Caption element when visible
];
}Default Behavior:
Usage Examples:
// Programmatically add caption to image
editor.model.change(writer => {
const imageElement = /* get image element */;
const captionElement = captionUtils.getCaptionFromImageElement(imageElement);
if (captionElement) {
// Add text to existing caption
writer.insertText('My image caption', captionElement, 'end');
}
});
// Insert image with caption
editor.execute('insertImage', {
source: 'image.jpg'
});
// Then add caption
editor.execute('toggleImageCaption');
// Add caption text
editor.model.change(writer => {
const selection = editor.model.document.selection;
writer.insertText('Beautiful landscape photo');
});Default CSS structure for captions:
.ck-content .image > figcaption {
display: table-caption;
caption-side: bottom;
word-break: break-word;
color: hsl(0, 0%, 20%);
background-color: hsl(0, 0%, 97%);
padding: .6em;
font-size: .75em;
outline-offset: -1px;
}