Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0),
Expand All @@ -21,6 +20,7 @@ and this project adheres to
- ♿ add document visible in list and openable via enter key #1365
- ♿ add pdf outline property to enable bookmarks display #1368
- ♿ hide decorative icons from assistive tech with aria-hidden #1404
- ♿ fix rgaa 1.9.1: convert to figure/figcaption structure #1426
- ♿ remove redundant aria-label to avoid over-accessibility #1420
- ♿ remove redundant aria-label on hidden icons and update tests #1432
- ♿ improve semantic structure and aria roles of leftpanel #1431
Expand All @@ -39,7 +39,6 @@ and this project adheres to
- ♿(frontend) improve accessibility:
- ♿improve NVDA navigation in DocShareModal #1396


## [3.7.0] - 2025-09-12

### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
imageRender,
imageToExternalHTML,
} from '@blocknote/core';
import { t } from 'i18next';

type ImageBlockConfig = typeof imageBlockConfig;

Expand All @@ -25,10 +26,73 @@ export const accessibleImageRender = (
const dom = imageRenderComputed.dom;
const imgSelector = dom.querySelector('img');

imgSelector?.setAttribute('alt', '');
imgSelector?.setAttribute('role', 'presentation');
imgSelector?.setAttribute('aria-hidden', 'true');
imgSelector?.setAttribute('tabindex', '-1');
const withCaption =
block.props.caption && dom.querySelector('.bn-file-caption');

const accessibleImageWithCaption = () => {
imgSelector?.setAttribute('alt', block.props.caption);
imgSelector?.removeAttribute('aria-hidden');
imgSelector?.setAttribute('tabindex', '0');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can add all this part in this function as well:

if (block.props.caption) {
const captionElement = dom.querySelector('.bn-file-caption');
if (captionElement) {
const figureElement = document.createElement('figure');
// Copy all attributes from the original div
figureElement.className = dom.className;
const styleAttr = dom.getAttribute('style');
if (styleAttr) {
figureElement.setAttribute('style', styleAttr);
}
figureElement.style.setProperty('margin', '0');
Array.from(dom.children).forEach((child) => {
figureElement.appendChild(child.cloneNode(true));
});
// Replace the <p> caption with <figcaption>
const figcaptionElement = document.createElement('figcaption');
const originalCaption = figureElement.querySelector('.bn-file-caption');
if (originalCaption) {
figcaptionElement.className = originalCaption.className;
figcaptionElement.textContent = originalCaption.textContent;
originalCaption.parentNode?.replaceChild(
figcaptionElement,
originalCaption,
);
// Add explicit role and aria-label for better screen reader support
figureElement.setAttribute('role', 'img');
figureElement.setAttribute(
'aria-label',
t(`Image: {{title}}`, { title: figcaptionElement.textContent }),
);
}
// Return the figure element as the new dom
return {
...imageRenderComputed,
dom: figureElement,
};
}
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indeed


// Fix RGAA 1.9.1: Convert to figure/figcaption structure if caption exists
const captionElement = dom.querySelector('.bn-file-caption');

if (captionElement) {
const figureElement = document.createElement('figure');
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

figure has a margin by default:
image

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch, I fixed it:
image


// Copy all attributes from the original div
figureElement.className = dom.className;
const styleAttr = dom.getAttribute('style');
if (styleAttr) {
figureElement.setAttribute('style', styleAttr);
}
figureElement.style.setProperty('margin', '0');

Array.from(dom.children).forEach((child) => {
figureElement.appendChild(child.cloneNode(true));
});

// Replace the <p> caption with <figcaption>
const figcaptionElement = document.createElement('figcaption');
const originalCaption = figureElement.querySelector('.bn-file-caption');
if (originalCaption) {
figcaptionElement.className = originalCaption.className;
figcaptionElement.textContent = originalCaption.textContent;
originalCaption.parentNode?.replaceChild(
figcaptionElement,
originalCaption,
);

// Add explicit role and aria-label for better screen reader support
figureElement.setAttribute('role', 'img');
figureElement.setAttribute(
'aria-label',
t(`Image: {{title}}`, { title: figcaptionElement.textContent }),
);
}

// Return the figure element as the new dom
return {
...imageRenderComputed,
dom: figureElement,
};
}
};

const accessibleImage = () => {
imgSelector?.setAttribute('alt', '');
imgSelector?.setAttribute('role', 'presentation');
imgSelector?.setAttribute('aria-hidden', 'true');
imgSelector?.setAttribute('tabindex', '-1');
};

// Set accessibility attributes for the image
const result = withCaption ? accessibleImageWithCaption() : accessibleImage();

// Return the result if accessibleImageWithCaption created a figure, otherwise return original
if (result) {
return result;
}

return {
...imageRenderComputed,
Expand Down
Loading