Version
1.63.0-next (reproduced on main at d5a185a, also on 1.62.1)
Steps to reproduce
No external repo needed, any failing screenshot comparison shows it.
- Write a test that fails
toMatchSnapshot / toHaveScreenshot on an image, run it with the html reporter.
- Open the report and expand the failing test. The image diff view shows a row of five mode switchers:
Diff, Actual, Expected, Side by side, Slider.
- Try to reach any of them with Tab and activate it with Enter.
Same row appears in the trace viewer attachments tab and in the html reporter error view.
As a runnable check against the existing story, this fails on main:
const component = await mount<typeof Default>('shared/imageDiffView/Default');
const sxs = component.getByRole('tab', { name: 'Side by side' });
await sxs.focus();
await expect(sxs).toBeFocused();
Expected behavior
The switchers take focus and Enter activates them, the way the tab strips do since #41434 and the html-reporter chips do since #42149.
Actual behavior
Tab skips the whole row. There is no way to change which image is displayed without a mouse, and a screen reader is never told the controls exist at all, because they carry no role.
packages/web/src/shared/imageDiffView.tsx:102-106 renders them as bare divs:
{diff.diff && <div style={{ ...modeStyle, fontWeight: mode === 'diff' ? 600 : 'initial' }} onClick={() => setMode('diff')}>Diff</div>}
<div style={{ ...modeStyle, fontWeight: mode === 'actual' ? 600 : 'initial' }} onClick={() => setMode('actual')}>Actual</div>
<div style={{ ...modeStyle, fontWeight: mode === 'expected' ? 600 : 'initial' }} onClick={() => setMode('expected')}>{expectedImageTitle}</div>
<div style={{ ...modeStyle, fontWeight: mode === 'sxs' ? 600 : 'initial' }} onClick={() => setMode('sxs')}>Side by side</div>
<div style={{ ...modeStyle, fontWeight: mode === 'slider' ? 600 : 'initial' }} onClick={() => setMode('slider')}>Slider</div>
No role, no tabIndex, no onKeyDown. Which one is active is also communicated only through fontWeight, so it is invisible to assistive tech even if you could reach them.
Additional context
ImageDiffView is shared, so this covers three surfaces: html-reporter/src/testResultView.tsx:150, html-reporter/src/testErrorView.tsx:53 and trace-viewer/src/ui/attachmentsTab.tsx:130.
I have a fix ready that follows the same native-element approach as #41434, buttons in a tablist plus a focus ring from --vscode-focusBorder, and I checked the rendered geometry is unchanged. Glad to send it over if you want to assign this to me.
sorry if I have got any of this wrong, I dug into it myself and used claude code to sanity check the approach against how the repo already does keyboard support. freshman in college, just trying to be genuinely useful here :)
Environment
System:
OS: macOS 26.5.2
CPU: (10) arm64 Apple M4
Binaries:
Node: 26.0.0
npm: 11.12.1
npmPackages:
playwright monorepo at main (1.63.0-next)
Version
1.63.0-next (reproduced on main at d5a185a, also on 1.62.1)
Steps to reproduce
No external repo needed, any failing screenshot comparison shows it.
toMatchSnapshot/toHaveScreenshoton an image, run it with the html reporter.Diff,Actual,Expected,Side by side,Slider.Same row appears in the trace viewer attachments tab and in the html reporter error view.
As a runnable check against the existing story, this fails on main:
Expected behavior
The switchers take focus and Enter activates them, the way the tab strips do since #41434 and the html-reporter chips do since #42149.
Actual behavior
Tab skips the whole row. There is no way to change which image is displayed without a mouse, and a screen reader is never told the controls exist at all, because they carry no role.
packages/web/src/shared/imageDiffView.tsx:102-106renders them as bare divs:No
role, notabIndex, noonKeyDown. Which one is active is also communicated only throughfontWeight, so it is invisible to assistive tech even if you could reach them.Additional context
ImageDiffViewis shared, so this covers three surfaces:html-reporter/src/testResultView.tsx:150,html-reporter/src/testErrorView.tsx:53andtrace-viewer/src/ui/attachmentsTab.tsx:130.I have a fix ready that follows the same native-element approach as #41434, buttons in a tablist plus a focus ring from
--vscode-focusBorder, and I checked the rendered geometry is unchanged. Glad to send it over if you want to assign this to me.sorry if I have got any of this wrong, I dug into it myself and used claude code to sanity check the approach against how the repo already does keyboard support. freshman in college, just trying to be genuinely useful here :)
Environment