You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Both verified on dev. So the newer demo app — added alongside the Fluent UI adapter (#278/#291) — regressed against the reference demo rather than making a deliberate choice: this is the stock
Blazor WASM template line, carried in unedited.
maximum-scale=1.0, user-scalable=no prevents a low-vision user from pinch-zooming on iOS Safari and
older Android browsers. That is a zoom-suppression failure of WCAG 2.1 SC 1.4.4 Resize Text
(Level AA), and it lands in a repository that has repeatedly treated accessibility conformance as a
hard requirement rather than a nicety — #199 (required-field annotation, Level A), #262 (file-upload
required state), #281 (focus after clearing an upload), #285 (ARIA state in the demo). A showcase app
that cannot be zoomed undercuts the thing it is showcasing.
Modern engines increasingly ignore user-scalable=no, which is mitigation, not a fix: Safari on iOS
respects maximum-scale, and the repo cannot control which engine a visitor uses.
Proposed solution
Drop the two scale clauses so the Fluent demo matches the MudBlazor demo:
One line, no behavioural risk — the layout is responsive either way; this only restores the user's
ability to zoom.
Then decide whether to guard it. The repo has the idiom for exactly this kind of
silently-regressing invariant (FormCraft.UnitTests/Ci/GitignoreTests, FormCraft.UnitTests/Ci/ClaudeMdTestCommandsTests): a static assertion that no demo app's viewport
meta contains user-scalable=no or maximum-scale costs almost nothing and catches the next app
scaffolded from the same template. The plan below includes it, since a second demo app already
reproduced the defect once.
Alternatives considered
Fix the line, no guard. Smallest change. Rejected as the sole measure: this exact regression
arrived by copying a template, and a third demo app would copy it again — the failure is invisible
in review because the line looks like boilerplate.
Keep user-scalable=no and rely on modern browsers ignoring it. Rejected: iOS Safari honours maximum-scale, so the barrier is real for a substantial audience, and shipping a known
accessibility defect in a showcase is the wrong signal for this repo.
Guard every accessibility attribute of the demo shells. Over-broad for a demo-only concern, and
hard to keep meaningful; the viewport is the one that silently disables a whole user capability.
FormCraft.DemoFluentApp is the showcase for the Fluent UI adapter, added with #278/#291. Its index.html came from the Blazor WASM template, whose default viewport meta suppresses zoom — a
long-standing template wart that predates the accessibility guidance now in WCAG.
The repo holds a high bar here: several of its recent fixes (#199, #262, #281, #285) exist purely to
correct accessibility defects, and CLAUDE.md records the reasoning for required-field annotation in
detail. Against that standard, shipping a demo that cannot be pinch-zoomed is an outlier — and it is
one nobody would spot in review, because the line reads as scaffolding.
Approaches
A. Fix the line. Delete maximum-scale=1.0, user-scalable=no. Pros: one line, removes the
barrier immediately, brings the app in line with its sibling. Cons: nothing stops the next
template-scaffolded app from reintroducing it.
B. Fix the line and add a Ci/ guard asserting no demo app's viewport disables scaling. Pros:
the repo already uses static Ci/ guards for invariants that regress silently, and this one has already regressed once by exactly the mechanism a guard catches. Cheap: a string assertion over two
files. Cons: one more test to maintain; arguably heavyweight for a demo.
C. Fix it and note it in CLAUDE.md.Pros: documents intent. Cons: documentation does not
fail a build, and the whole point is that this is invisible to reviewers.
Recommendation
B. A alone is the fix, but the evidence for the guard is unusually direct: there are two demo
apps, one has the defect and one does not, and the difference arrived by copying a template. That is
the precise situation the repo's existing Ci/ guards were written for. C adds a sentence nothing
enforces.
📋 Spec
Goal
No demo application ships a viewport that disables user scaling, and a future one cannot silently
reintroduce it.
Scope
FormCraft.DemoFluentApp/wwwroot/index.html — the viewport meta.
A Ci/ guard asserting demo viewport metas do not suppress zoom.
Match case-insensitively and tolerate whitespace variations (user-scalable = no).
A future demo app must be picked up automatically — glob the demo wwwroot/index.html files rather
than hard-coding two paths, or the guard silently ignores app number three.
Assumptions
Both demo apps keep a wwwroot/index.html shell (true for Blazor WASM).
🛠️ Implementation plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.
Goal: restore pinch-zoom in the Fluent demo, and guard it so a scaffolded app cannot remove it again.
Architecture: demo shell markup plus one static Ci/ invariant test. No library code changes.
Base branch dev; commit as Philippe Matray <phmatray@gmail.com>; conventional commits.
⛔ Do not modify library markup or FormCraft.DemoBlazorApp — it is already correct and serves as the reference.
TreatWarningsAsErrors=true is deliberate — do not relax it.
dotnet test --filter is inert here (MTP). Use dotnet test <csproj> -c Release -- --filter-class <FQN>, or the built host directly; see .claude/skills/repo-profile.md → Build & test.
Task 1: Guard the invariant (failing test first)
Files: create FormCraft.UnitTests/Ci/DemoViewportTests.cs; read FormCraft.UnitTests/Ci/GitignoreTests.cs for the repo-root pattern.
Interfaces: xUnit facts over every demo wwwroot/index.html found under the repo root.
Step 1: Reuse WorkflowSource.RepoRoot (as GitignoreTests does) and glob every */wwwroot/index.html under the repo root, so a future demo app is covered without editing the test.
Step 3: Write the failing assertion: no viewport meta may contain user-scalable=no or maximum-scale (case-insensitive, whitespace-tolerant), naming the offending file.
Step 4: Run it → FAIL, naming FormCraft.DemoFluentApp/wwwroot/index.html. Record the output.
Step 5: Commit: test(ci): pin that no demo viewport disables user scaling.
Problem / motivation
FormCraft.DemoFluentAppships a viewport meta that disables pinch-zoom:The established sibling demo does not:
Both verified on
dev. So the newer demo app — added alongside the Fluent UI adapter (#278/#291) —regressed against the reference demo rather than making a deliberate choice: this is the stock
Blazor WASM template line, carried in unedited.
maximum-scale=1.0, user-scalable=noprevents a low-vision user from pinch-zooming on iOS Safari andolder Android browsers. That is a zoom-suppression failure of WCAG 2.1 SC 1.4.4 Resize Text
(Level AA), and it lands in a repository that has repeatedly treated accessibility conformance as a
hard requirement rather than a nicety — #199 (required-field annotation, Level A), #262 (file-upload
required state), #281 (focus after clearing an upload), #285 (ARIA state in the demo). A showcase app
that cannot be zoomed undercuts the thing it is showcasing.
Modern engines increasingly ignore
user-scalable=no, which is mitigation, not a fix: Safari on iOSrespects
maximum-scale, and the repo cannot control which engine a visitor uses.Proposed solution
Drop the two scale clauses so the Fluent demo matches the MudBlazor demo:
One line, no behavioural risk — the layout is responsive either way; this only restores the user's
ability to zoom.
Then decide whether to guard it. The repo has the idiom for exactly this kind of
silently-regressing invariant (
FormCraft.UnitTests/Ci/GitignoreTests,FormCraft.UnitTests/Ci/ClaudeMdTestCommandsTests): a static assertion that no demo app's viewportmeta contains
user-scalable=noormaximum-scalecosts almost nothing and catches the next appscaffolded from the same template. The plan below includes it, since a second demo app already
reproduced the defect once.
Alternatives considered
arrived by copying a template, and a third demo app would copy it again — the failure is invisible
in review because the line looks like boilerplate.
user-scalable=noand rely on modern browsers ignoring it. Rejected: iOS Safari honoursmaximum-scale, so the barrier is real for a substantial audience, and shipping a knownaccessibility defect in a showcase is the wrong signal for this repo.
hard to keep meaningful; the viewport is the one that silently disables a whole user capability.
Area
Demo applications —
FormCraft.DemoFluentAppshell markup; accessibilityFollow-up from #328. Related: #285, #281, #262, #199
🧠 Brainstorm
Problem / context
FormCraft.DemoFluentAppis the showcase for the Fluent UI adapter, added with #278/#291. Itsindex.htmlcame from the Blazor WASM template, whose default viewport meta suppresses zoom — along-standing template wart that predates the accessibility guidance now in WCAG.
The repo holds a high bar here: several of its recent fixes (#199, #262, #281, #285) exist purely to
correct accessibility defects, and
CLAUDE.mdrecords the reasoning for required-field annotation indetail. Against that standard, shipping a demo that cannot be pinch-zoomed is an outlier — and it is
one nobody would spot in review, because the line reads as scaffolding.
Approaches
A. Fix the line. Delete
maximum-scale=1.0, user-scalable=no. Pros: one line, removes thebarrier immediately, brings the app in line with its sibling. Cons: nothing stops the next
template-scaffolded app from reintroducing it.
B. Fix the line and add a
Ci/guard asserting no demo app's viewport disables scaling. Pros:the repo already uses static
Ci/guards for invariants that regress silently, and this one hasalready regressed once by exactly the mechanism a guard catches. Cheap: a string assertion over two
files. Cons: one more test to maintain; arguably heavyweight for a demo.
C. Fix it and note it in
CLAUDE.md. Pros: documents intent. Cons: documentation does notfail a build, and the whole point is that this is invisible to reviewers.
Recommendation
B. A alone is the fix, but the evidence for the guard is unusually direct: there are two demo
apps, one has the defect and one does not, and the difference arrived by copying a template. That is
the precise situation the repo's existing
Ci/guards were written for. C adds a sentence nothingenforces.
📋 Spec
Goal
No demo application ships a viewport that disables user scaling, and a future one cannot silently
reintroduce it.
Scope
FormCraft.DemoFluentApp/wwwroot/index.html— the viewport meta.Ci/guard asserting demo viewport metas do not suppress zoom.Non-goals
Behaviour
flowchart TD A["DemoFluentApp index.html<br/>maximum-scale=1.0, user-scalable=no"] --> B["iOS Safari honours maximum-scale"] B --> C["low-vision user cannot pinch-zoom<br/>WCAG 2.1 SC 1.4.4 ❌"] D["DemoBlazorApp index.html<br/>width=device-width, initial-scale=1.0"] --> E["zoom works ✅"] F["Ci guard: no demo viewport may carry<br/>user-scalable=no / maximum-scale"] --> EKey files
FormCraft.DemoFluentApp/wwwroot/index.html(line 6) — the file changed.FormCraft.DemoBlazorApp/wwwroot/index.html(line 6) — the correct reference; not modified.FormCraft.UnitTests/Ci/GitignoreTests.cs— the guard idiom to copy (repo-root resolution viaWorkflowSource.RepoRoot).Validation rules
index.htmlviewport containsuser-scalable=noormaximum-scale.vacuously (the mistake corrected in
ClaudeMdTestCommandsTestsunder CLAUDE.md still teaches VSTest test commands that Microsoft.Testing.Platform silently ignores #299).Edge cases
user-scalable = no).wwwroot/index.htmlfiles ratherthan hard-coding two paths, or the guard silently ignores app number three.
Assumptions
wwwroot/index.htmlshell (true for Blazor WASM).🛠️ Implementation plan
Goal: restore pinch-zoom in the Fluent demo, and guard it so a scaffolded app cannot remove it again.
Architecture: demo shell markup plus one static
Ci/invariant test. No library code changes.Tech stack: .NET 10 SDK pinned by
global.json(10.0.302), Blazor WASM, xUnit + Shouldly.Global constraints:
dev; commit asPhilippe Matray <phmatray@gmail.com>; conventional commits.FormCraft.DemoBlazorApp— it is already correct and serves as the reference.TreatWarningsAsErrors=trueis deliberate — do not relax it.dotnet test --filteris inert here (MTP). Usedotnet test <csproj> -c Release -- --filter-class <FQN>, or the built host directly; see.claude/skills/repo-profile.md→ Build & test.Task 1: Guard the invariant (failing test first)
Files: create
FormCraft.UnitTests/Ci/DemoViewportTests.cs; readFormCraft.UnitTests/Ci/GitignoreTests.csfor the repo-root pattern.Interfaces: xUnit facts over every demo
wwwroot/index.htmlfound under the repo root.WorkflowSource.RepoRoot(asGitignoreTestsdoes) and glob every*/wwwroot/index.htmlunder the repo root, so a future demo app is covered without editing the test.ClaudeMdTestCommandsTestsunder CLAUDE.md still teaches VSTest test commands that Microsoft.Testing.Platform silently ignores #299).user-scalable=noormaximum-scale(case-insensitive, whitespace-tolerant), naming the offending file.FormCraft.DemoFluentApp/wwwroot/index.html. Record the output.test(ci): pin that no demo viewport disables user scaling.Task 2: Restore pinch-zoom and verify
Files: modify
FormCraft.DemoFluentApp/wwwroot/index.html(line 6).Interfaces: none.
<meta name="viewport" content="width=device-width, initial-scale=1.0" />, matchingFormCraft.DemoBlazorApp../build.sh Test(CI gate) → all suites green underTreatWarningsAsErrors.fix(demo): allow pinch-zoom in the Fluent UI demo.