Background
Surfaced by Critique Guardian during review of upstream PR Light-Heart-Labs#1019. The PR added a11y tests for the TemplatePicker decorative status icons, originally with a bulk container.querySelectorAll('svg') selector. The maintainer audit and CG review both flagged that this bulk selector caught an unrelated SVG: the HardDrive disk-size glyph rendered next to the ~XGB label inside each card.
In Light-Heart-Labs#1019 the test selector was narrowed (div.rounded-lg svg) so the test only asserts the four status icons (Loader2 / AlertTriangle / Check / default Icon). That keeps the test PR's scope to tests only.
This issue is the production-code follow-up the CG explicitly recommended ("Worth a separate issue if the team wants strict a11y coverage").
File
dream-server/extensions/services/dashboard/src/components/TemplatePicker.jsx:96
{tmpl.estimated_disk_gb && (
<span className="flex items-center gap-1">
<HardDrive size={10} /> {/* ← missing aria-hidden="true" */}
~{tmpl.estimated_disk_gb}GB
</span>
)}
Why this is a real a11y gap
- The adjacent text
~{tmpl.estimated_disk_gb}GB (e.g. "~12GB") carries the full semantic meaning.
- The
HardDrive icon is purely decorative — it adds visual context for sighted users only.
- Screen readers will announce the glyph (some as "img", some as "graphic") which adds noise without conveying information that isn't already in the adjacent text.
- All four status icons in the same component (
Loader2, AlertTriangle, Check, Icon) already carry aria-hidden="true" — HardDrive is the lone outlier in the picker card.
Proposed fix
Single-line edit:
<HardDrive size={10} aria-hidden="true" />
Once that lands, the a11y test in TemplatePicker.a11y.test.jsx could optionally widen its selector back to container.querySelectorAll('svg') to assert the property holds for every SVG in the picker — but that's a bonus, not required. The narrowed-selector test added by Light-Heart-Labs#1019 will continue to pass either way.
Scope
- Single line in a single file.
- No additional dependencies, no new imports.
- Same
aria-hidden pattern already used 4× in the same file (lines 66, 68, 70, 71).
- TemplatePreview modal (rendered after a card click, lines 127–308) has additional unhidden SVGs (
Loader2 line 201, Check lines 227/268, AlertTriangle line 240, Icon line 186, Loader2 line 308). Those are out of scope for this issue — they sit in the preview modal, not the picker cards. A separate audit pass could decide which of those are decorative vs informational.
Reference
Background
Surfaced by Critique Guardian during review of upstream PR Light-Heart-Labs#1019. The PR added a11y tests for the TemplatePicker decorative status icons, originally with a bulk
container.querySelectorAll('svg')selector. The maintainer audit and CG review both flagged that this bulk selector caught an unrelated SVG: theHardDrivedisk-size glyph rendered next to the~XGBlabel inside each card.In Light-Heart-Labs#1019 the test selector was narrowed (
div.rounded-lg svg) so the test only asserts the four status icons (Loader2 / AlertTriangle / Check / default Icon). That keeps the test PR's scope to tests only.This issue is the production-code follow-up the CG explicitly recommended ("Worth a separate issue if the team wants strict a11y coverage").
File
dream-server/extensions/services/dashboard/src/components/TemplatePicker.jsx:96Why this is a real a11y gap
~{tmpl.estimated_disk_gb}GB(e.g. "~12GB") carries the full semantic meaning.HardDriveicon is purely decorative — it adds visual context for sighted users only.Loader2,AlertTriangle,Check,Icon) already carryaria-hidden="true"—HardDriveis the lone outlier in the picker card.Proposed fix
Single-line edit:
Once that lands, the a11y test in
TemplatePicker.a11y.test.jsxcould optionally widen its selector back tocontainer.querySelectorAll('svg')to assert the property holds for every SVG in the picker — but that's a bonus, not required. The narrowed-selector test added by Light-Heart-Labs#1019 will continue to pass either way.Scope
aria-hiddenpattern already used 4× in the same file (lines 66, 68, 70, 71).Loader2line 201,Checklines 227/268,AlertTriangleline 240,Iconline 186,Loader2line 308). Those are out of scope for this issue — they sit in the preview modal, not the picker cards. A separate audit pass could decide which of those are decorative vs informational.Reference