Block Editor: Add a caption field to image properties
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 970
- Forks
- 486
- Avg merge
- 3d 33m
- Merged PRs (30d)
- 170
Description
Description
Add a caption field to the image properties dialog in the Block Editor (libs/new-block-editor), persist it as a new attribute on the dotImage node, and render it as a <figcaption> across every renderer.
Today the dialog exposes three fields — Image URL (src), Tooltip (title) and Alt text (alt). There is no way to attach a visible caption to an image. title is the browser tooltip and must stay that way; the caption is a distinct, visible piece of content.
Current state (verified)
- Dialog template:
core-web/libs/new-block-editor/src/lib/editor/components/image-popover/image-popover.component.html— three controls, all bound toform.controls.{src,title,alt}. - Node:
core-web/libs/new-block-editor/src/lib/editor/extensions/nodes/image.extension.ts—DotImagealready serializes to<figure>in bothrenderHTML()andaddNodeView(), so<figcaption>has a natural place to live. - VTL renderer:
dotCMS/src/main/webapp/WEB-INF/velocity/static/storyblock/dotImage.vtl— already emits a<figure>wrapper.
Design decision
A new caption node attribute, rendered as <figcaption> inside the existing <figure>. title keeps its current meaning (tooltip). No fallback from title to caption — they are independent fields.
Files in scope
| File | Change |
|---|---|
.../components/image-popover/image-popover.component.html |
Add the Caption input |
.../components/image-popover/image-popover.component.ts |
Add caption to the form group; read/write the node attr |
.../extensions/nodes/image.extension.ts |
Add caption attribute with parseHTML / renderHTML; emit <figcaption> in renderHTML() and addNodeView() |
dotCMS/src/main/webapp/WEB-INF/messages/Language.properties |
New keys: ...field.caption.label, ...field.caption.hint, ...field.caption.placeholder |
dotCMS/src/main/webapp/WEB-INF/velocity/static/storyblock/dotImage.vtl |
Emit <figcaption> when caption is set |
dotCMS/src/main/java/com/dotcms/tiptap/TiptapHtml.java |
Emit <figcaption> |
dotCMS/src/main/java/com/dotcms/tiptap/TiptapMarkdown.java |
Emit the caption in Markdown output |
core-web/libs/sdk/react/.../blocks/Image.tsx |
Render <figcaption> |
core-web/libs/sdk/vue/.../blocks/DotImage.vue |
Render <figcaption> |
core-web/libs/sdk/angular/.../blocks/image.component.ts |
Render <figcaption> |
core-web/libs/sdk/angular/.../dotcms-block-editor-renderer-native.component.html |
Render <figcaption> |
core-web/libs/sdk/types/src/lib/components/block-editor-renderer/internal.ts |
Add caption to the image attrs type |
Acceptance Criteria
Editor — happy path
- The image properties dialog shows a "Caption" text input below Alt text
- Typing a caption and clicking Save persists it as the
captionattribute on thedotImagenode - A saved caption appears as visible text directly below the image in the editor canvas
- Reopening the dialog on an image with a caption pre-populates the Caption input with the stored value
- Clearing the Caption input and saving removes the caption text and the
<figcaption>element from the image
Editor — field independence
- Setting a caption does not change the
title(tooltip) attribute - Setting a tooltip does not change the
captionattribute - The Caption input is optional — saving with it empty succeeds and
srcremains the only required field
Persistence & round-trip
- The stored contentlet JSON contains
captionin thedotImagenode'sattrs - Copying an image with a caption and pasting it elsewhere in the document preserves the caption
-
parseHTMLreads a caption back from a<figure><img><figcaption>…</figcaption></figure>structure
Renderers
- VTL (
dotImage.vtl) renders<figcaption>with the caption text whencaptionis set - VTL renders no
<figcaption>element whencaptionis unset, empty, or the literal string"null" - React SDK block renderer renders
<figcaption>with the caption text - Vue SDK block renderer renders
<figcaption>with the caption text - Angular SDK block renderer (
image.component.ts) renders<figcaption>with the caption text - Angular SDK native/semantic renderer renders
<figcaption>with the caption text -
TiptapHtmlserver-side HTML output includes the<figcaption> -
TiptapMarkdownoutput includes the caption text
Layout interaction
- A captioned image with
textWrapset keeps theimage-wrap-*figure class and the caption stays inside the wrapped figure - A captioned image with
textAlignset keeps theimage-align-*figure class - A captioned image wrapped in a link renders the
<figcaption>outside the<a>, not inside it
Backward compatibility
- Existing stored images with no
captionattribute render exactly as they do today — no<figcaption>, no layout shift
Escaping
- A caption containing
<,>,&, or"is HTML-escaped in every renderer and does not inject markup
Tests
- Unit specs in
libs/new-block-editor/cover the dialog field, node attribute round-trip, and<figcaption>serialization - SDK renderer specs updated for React, Vue, and both Angular renderers
Priority
Medium
Additional Context
- Scope is
libs/new-block-editoronly. The legacylibs/block-editoris not in scope. - Related: the image resize ticket (#37495) touches the same node and the same renderer set — coordinate to avoid conflicting edits to
image.extension.tsanddotImage.vtl. - Related: the message-key audit ticket (#37497) fixes the Tooltip field's misleading "Add a caption…" placeholder. That fix and this feature must land consistently — the tooltip placeholder must not say "caption" once a real Caption field exists.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the image popover files and image.extension.ts under core-web/libs/new-block-editor, then trace the existing figure output in dotImage.vtl. Review the listed Java and SDK renderer files and their existing unit specs. Done means caption is persisted, parsed, escaped, and rendered consistently across all listed renderers without changing tooltip behavior or unc captioned images.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- angular, java, react, typescript
- Domain
- backend, content, frontend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 70/100