Repository navigation
Description
- I have searched the existing issues to make sure this bug has not already been reported.
Describe the Bug
CheckBox.value is a booleanReference, so a literal, a {"path": ...} binding and a {"call": ...} are all valid. A literal is dropped: the component renders unchecked and announces itself unchecked, with nothing logged. The agent says the setting is on, the user sees it off, and neither side is told.
check_box.dart binds the widget to a data model path and never consults what the agent sent:
final path = (valueRef is Map && valueRef.containsKey('path'))
? valueRef['path'] as String
: '${itemContext.id}.value';
...
BoundBool(
dataContext: itemContext.dataContext,
value: {'path': path}, // the literal is never read
builder: (context, value) => CheckboxListTile(value: value ?? false, ...),
)slider.dart has exactly the fallback this is missing:
var effectiveValue = value;
if (effectiveValue == null) {
if (valueRef is num) {
effectiveValue = valueRef;
}
}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('CheckBox reflects a literal value', (tester) async {
final catalog = BasicCatalogItems.asCatalog().copyWith(catalogId: 'repro');
final controller = SurfaceController(catalogs: [catalog]);
controller.handleMessage(core.UpdateComponentsMessage(surfaceId: 's', components: [
{'id': 'root', 'component': 'CheckBox', 'label': 'Wi-Fi', 'value': true},
]));
controller.handleMessage(
core.CreateSurfaceMessage(surfaceId: 's', catalogId: 'repro'));
await tester.pumpWidget(MaterialApp(
home: Scaffold(body: Surface(surfaceContext: controller.contextFor('s')))));
await tester.pumpAndSettle();
expect(tester.widget<Checkbox>(find.byType(Checkbox)).value, isTrue);
});
}Expected: true
Actual: <false>
The same surface with "value": {"path": "/on"} and an updateDataModel of {"on": true} renders checked, so only the literal is affected. In the semantics tree the node reads checked=false, so a screen reader is told the same wrong thing the screen shows.
Expected Behavior
A literal value is what the checkbox shows until something writes to the path, the way Slider and TextField already behave.
Environment Details
- OS: macOS 26.5.2
- Browser/Platform: Flutter 3.44.6 stable, Dart 3.10
- SDK/Package Name & Version: genui 0.10.3 (
main, d88aa76), a2ui_core 0.1.1 - Protocol Version: v0.9.1
Additional Context
Found while prototyping a rendering conformance suite that states what a surface must expose as semantics — role, name, value, state, actions — so the same cases can be run against Flutter, SwiftUI, Compose and the web. The case declared checked: true and this renderer reported checked=false.
Happy to send the PR.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsDone
Activity
diegolopezrm commentedon Sep 22, 2026
The prototype this came out of is written up in #2738, in case the shape of the suite is worth discussing separately from the fix.
josemontespg commentedon Sep 22, 2026
A2UI Triage: Confirmed on genui main (d88aa76):
check_box.dartalways bindsBoundBoolto{path}and never reads a literal, whileslider.dartandtext_field.dartfall back to the literal when the path is empty. The spec'sDynamicBooleanallows a literal and genui's ownbooleanReferencedoc says so, so this is a bug.Marked P2 and
size: small. A PR is welcome: mirror the Slider fallback (use the literal until the path has a value) and add a widget test like the one in your report. Same area as #2737, so both could land together. cc @gspencergoog to decide if we'd like to accept a PR from the community or assign the issue to the a2ui team.diegolopezrm commentedon Sep 22, 2026
PR is up: flutter/genui#1038. It mirrors the
Sliderfallback as suggested, with a test for the literal and one for a binding still taking over from it.@gspencergoog, same question as on #2737 — happy for you to take it instead if the team would rather own the fix.