Skip to content

Block Editor: Add a caption field to image properties #37496

Description

@rjvelazco

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 to form.controls.{src,title,alt}.
  • Node: core-web/libs/new-block-editor/src/lib/editor/extensions/nodes/image.extension.tsDotImage already serializes to <figure> in both renderHTML() and addNodeView(), 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 caption attribute on the dotImage node
  • 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 caption attribute
  • The Caption input is optional — saving with it empty succeeds and src remains the only required field

Persistence & round-trip

  • The stored contentlet JSON contains caption in the dotImage node's attrs
  • Copying an image with a caption and pasting it elsewhere in the document preserves the caption
  • parseHTML reads a caption back from a <figure><img><figcaption>…</figcaption></figure> structure

Renderers

  • VTL (dotImage.vtl) renders <figcaption> with the caption text when caption is set
  • VTL renders no <figcaption> element when caption is 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
  • TiptapHtml server-side HTML output includes the <figcaption>
  • TiptapMarkdown output includes the caption text

Layout interaction

  • A captioned image with textWrap set keeps the image-wrap-* figure class and the caption stays inside the wrapped figure
  • A captioned image with textAlign set keeps the image-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 caption attribute 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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions