Repository navigation
Description
- I have searched the existing issues to make sure this bug has not already been reported.
Describe the Bug
The basic catalog's Image carries the text a screen reader is supposed to announce, and genui neither accepts it nor announces anything.
The spec declares it on the component itself:
"description": {
"$ref": "common_types.json#/$defs/DynamicString",
"description": "Accessibility text for the image."
}web_core declares the same property in its basic catalog. genui's image.dart schema has url, fit and variant, and nothing else, and no widget under packages/genui/lib passes a semanticLabel.
So an image is the one component whose entire accessible name has to come from the agent, and it is the one component that drops it.
Steps to Reproduce
import 'package:a2ui_core/a2ui_core.dart' as core;
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:genui/genui.dart';
void main() {
testWidgets('Image with the spec description', (tester) async {
final catalog = BasicCatalogItems.asCatalog().copyWith(catalogId: 'repro');
final controller = SurfaceController(catalogs: [catalog]);
controller.handleMessage(core.UpdateComponentsMessage(surfaceId: 's', components: [
{
'id': 'root',
'component': 'Image',
'url': 'https://example.com/chart.png',
'description': 'Chart of weekly usage',
},
]));
controller.handleMessage(core.CreateSurfaceMessage(surfaceId: 's', catalogId: 'repro'));
final handle = tester.ensureSemantics();
await tester.pumpWidget(MaterialApp(
home: Scaffold(body: Surface(surfaceContext: controller.contextFor('s')))));
await tester.pumpAndSettle();
final node = tester.getSemantics(find.byType(Image).first);
expect(node.label, equals('Chart of weekly usage'));
expect(node.getSemanticsData().flagsCollection.isImage, isTrue);
handle.dispose();
controller.dispose();
});
}Measured on genui main (171a4bb): the image renders, so the property is accepted and then ignored, Image.semanticLabel is null, the semantics node's label is empty and isImage is false. Assistive technology gets an unnamed node that is not even announced as an image.
Expected Behavior
description is part of the component's schema and reaches Image(semanticLabel:), which also gives the node the image role. It is a DynamicString, so a {"path": ...} or a {"call": ...} resolves like any other property.
Environment Details
- OS: macOS 26.5.2
- Browser/Platform: Flutter 3.44.6 stable, Dart 3.12.2
- SDK/Package Name & Version: genui at main (171a4bb), a2ui_core 0.1.1
- Protocol Version: v0.9.1
Additional Context
This is the Image role gap from #2738, filed separately as asked there.
It is next to #2697 but not the same thing. That issue is about ComponentCommon.accessibility being dropped for every component; this one is about the property the basic catalog puts on Image itself, which would still not arrive once the generic wrapper lands, and about the node not carrying the image role. It is also one of the basic catalog divergences between genui and web_core mentioned in #2738.
Happy to send the PR alongside the one for #2697, since both land in the same area.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
nan-yu commentedon Sep 25, 2026
A2UI Triage: Confirmed. The basic catalog specification declares
descriptiononImageas accessibility text (DynamicString), whichweb_coreimplements. Ingenui,image.dartomitsdescriptionfrom the component schema and does not passsemanticLabelto Flutter'sImagewidget, leaving the image without an accessible name.Marked P2 and
size: small, and assigned to @polina-c. A PR is welcome since you mentioned you are happy to send one alongside #2697; cc @polina-c to coordinate.diegolopezrm commentedon Sep 25, 2026
This is a duplicate of #2740, which I filed on the 22nd and completely missed when I opened this one. Sorry for the double triage. Closing this, #2740 already has gspencergoog assigned.