What Narrator hears when it opens DetentShell

DetentShell · August 2026 · 3 min read

Turn on Narrator and tab across the toolbar of most home-grown developer tools. You’ll hear “button.” Then “button” again. Fourteen times, if the toolbar is icon-only.

For a while, ours was one of them. DetentShell’s toolbar is icon-only on purpose, because that’s the ISE look, and icons don’t carry accessible names. The tooltips had the information. Tooltips are for people who can hover. The UI Automation tree, which is what Narrator reads, had blank name fields.

The fix took an afternoon. Each control got a proper automation name: Run Script, Run Selection, Stop, Continue, Clear Console, and so on, seventeen in all. The harder question was how to keep it fixed, because accessibility work decays. Somebody adds a button next year and forgets the name, and nobody notices, because nobody on a small team runs a screen reader every day.

Our answer came from infrastructure we already had. DetentShell’s UI tests drive the real app through UI Automation, the same tree Narrator walks. So we added a scenario that counts: find the toolbar, enumerate every interactive control, fail if any name is empty. It runs in a clean Windows Sandbox against the release build, every release.

That test earned its keep immediately. On its first run it reported sixteen named controls out of seventeen. The stray was the toolbar’s overflow chevron, a control that lives inside WPF’s toolbar template where XAML attributes can’t reach it. We had to name it from code after the template loads. Without the count, we’d have shipped it anonymous.

Names were the loudest gap. The quieter ones were about state. The editor now reports caret position, selection, fold counts, and zoom level through its automation status. The breakpoint gutter, which paints its dots directly onto a margin and would otherwise be invisible to assistive tech, reports its whole set as text, including which breakpoints are disabled. A sighted user sees a dimmed dot; a Narrator user now gets the same fact. The console exposes its full output text through the standard Value pattern, so “read me the output” means all of it, not just the rows currently rendered.

Keyboard access mostly came free, since the ISE tradition is keyboard-dense and we kept every gesture. It still surprised us once: our automated tests, which press real keys, found a bug where F5 at a breakpoint did nothing while the toolbar Continue button worked fine. Mouse-only testing would never have caught it. Keyboard-first testing means keyboard-only users get the same product everyone else does.

Contrast is checked the same way. Every theme, including High Contrast, has every text and background pair computed against the WCAG AA ratio in the unit suite, and a failing pair fails the build. That rule dates to a real bug, a tab label that was invisible in one theme.

There’s still a human step. Before a release, someone sits down with Narrator and listens to the core workflow, because a correct tree and a good experience aren’t the same thing. But the floor is no longer held up by anyone’s memory. It’s held up by tests.

← All posts