Skip to content

Commit d0c9de9

Browse files
committed
✨(frontend) set empty alt for decorative images in blocknote editor
ensure decorative images have empty alt to comply with RGAA 1.2 accessibility Signed-off-by: Cyril <[email protected]>
1 parent 81f3997 commit d0c9de9

File tree

7 files changed

+68
-6
lines changed

7 files changed

+68
-6
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ and this project adheres to
1818
- #1262
1919
- #1244
2020
- #1270
21+
- #1282
2122

2223
### Fixed
2324

2425
- 🐛(makefile) Windows compatibility fix for Docker volume mounting #1264
2526
- 🐛(minio) fix user permission error with Minio and Windows #1264
2627

27-
2828
## [3.5.0] - 2025-07-31
2929

3030
### Added

src/frontend/apps/e2e/__tests__/app-impress/config.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,9 @@ test.describe('Config', () => {
4343
path.join(__dirname, 'assets/logo-suite-numerique.png'),
4444
);
4545

46-
const image = page.getByRole('img', { name: 'logo-suite-numerique.png' });
46+
const image = page
47+
.locator('.--docs--editor-container img.bn-visual-media')
48+
.first();
4749

4850
await expect(image).toBeVisible();
4951

src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,9 @@ test.describe('Doc Editor', () => {
272272
path.join(__dirname, 'assets/logo-suite-numerique.png'),
273273
);
274274

275-
const image = page.getByRole('img', { name: 'logo-suite-numerique.png' });
275+
const image = page
276+
.locator('.--docs--editor-container img.bn-visual-media')
277+
.first();
276278

277279
await expect(image).toBeVisible();
278280

@@ -284,6 +286,11 @@ test.describe('Doc Editor', () => {
284286
expect(await image.getAttribute('src')).toMatch(
285287
/http:\/\/localhost:8083\/media\/.*\/attachments\/.*.png/,
286288
);
289+
290+
await expect(image).toHaveAttribute('role', 'presentation');
291+
await expect(image).toHaveAttribute('alt', '');
292+
await expect(image).toHaveAttribute('tabindex', '-1');
293+
await expect(image).toHaveAttribute('aria-hidden', 'true');
287294
});
288295

289296
test('it checks the AI buttons', async ({ page, browserName }) => {

src/frontend/apps/e2e/__tests__/app-impress/doc-export.spec.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,9 @@ test.describe('Doc Export', () => {
122122
const fileChooser = await fileChooserPromise;
123123
await fileChooser.setFiles(path.join(__dirname, 'assets/test.svg'));
124124

125-
const image = page.getByRole('img', { name: 'test.svg' });
125+
const image = page
126+
.locator('.--docs--editor-container img.bn-visual-media')
127+
.first();
126128

127129
await expect(image).toBeVisible();
128130

@@ -182,7 +184,9 @@ test.describe('Doc Export', () => {
182184
const fileChooser = await fileChooserPromise;
183185
await fileChooser.setFiles(path.join(__dirname, 'assets/test.svg'));
184186

185-
const image = page.getByRole('img', { name: 'test.svg' });
187+
const image = page
188+
.locator('.--docs--editor-container img.bn-visual-media')
189+
.first();
186190

187191
await expect(image).toBeVisible();
188192

src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,11 @@ import { randomColor } from '../utils';
3333

3434
import { BlockNoteSuggestionMenu } from './BlockNoteSuggestionMenu';
3535
import { BlockNoteToolbar } from './BlockNoteToolBar/BlockNoteToolbar';
36-
import { CalloutBlock, DividerBlock } from './custom-blocks';
36+
import {
37+
AccessibleImageBlock,
38+
CalloutBlock,
39+
DividerBlock,
40+
} from './custom-blocks';
3741
import {
3842
InterlinkingLinkInlineContent,
3943
InterlinkingSearchInlineContent,
@@ -50,6 +54,7 @@ const baseBlockNoteSchema = withPageBreak(
5054
...defaultBlockSpecs,
5155
callout: CalloutBlock,
5256
divider: DividerBlock,
57+
image: AccessibleImageBlock,
5358
},
5459
inlineContentSpecs: {
5560
...defaultInlineContentSpecs,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import {
2+
BlockFromConfig,
3+
BlockNoteEditor,
4+
BlockSchemaWithBlock,
5+
InlineContentSchema,
6+
StyleSchema,
7+
createBlockSpec,
8+
imageBlockConfig,
9+
imageParse,
10+
imageRender,
11+
imageToExternalHTML,
12+
} from '@blocknote/core';
13+
14+
type ImageBlockConfig = typeof imageBlockConfig;
15+
16+
export const accessibleImageRender = (
17+
block: BlockFromConfig<ImageBlockConfig, InlineContentSchema, StyleSchema>,
18+
editor: BlockNoteEditor<
19+
BlockSchemaWithBlock<ImageBlockConfig['type'], ImageBlockConfig>,
20+
InlineContentSchema,
21+
StyleSchema
22+
>,
23+
) => {
24+
const imageRenderComputed = imageRender(block, editor);
25+
const dom = imageRenderComputed.dom;
26+
const imgSelector = dom.querySelector('img');
27+
28+
imgSelector?.setAttribute('alt', '');
29+
imgSelector?.setAttribute('role', 'presentation');
30+
imgSelector?.setAttribute('aria-hidden', 'true');
31+
imgSelector?.setAttribute('tabindex', '-1');
32+
33+
return {
34+
...imageRenderComputed,
35+
dom,
36+
};
37+
};
38+
39+
export const AccessibleImageBlock = createBlockSpec(imageBlockConfig, {
40+
render: accessibleImageRender,
41+
parse: imageParse,
42+
toExternalHTML: imageToExternalHTML,
43+
});
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
export * from './AccessibleImageBlock';
12
export * from './CalloutBlock';
23
export * from './DividerBlock';

0 commit comments

Comments
 (0)