A side-by-side code diff is visually efficient. It can become incoherent when assistive technology reads the entire old file and then the entire new file.
Start with one semantic sequence of changes. Treat split view as a presentation of that sequence, not as the document structure.
Model hunks first
type DiffLine = {
oldNumber?: number;
newNumber?: number;
kind: "context" | "removed" | "added";
text: string;
};
type DiffHunk = {
id: string;
heading: string;
lines: DiffLine[];
};
Render each hunk as a labelled region with a summary and navigation target:
<nav aria-label="Changed sections">
<a href="#hunk-parser">Parser: lines 18–31</a>
</nav>
<section id="hunk-parser" aria-labelledby="hunk-parser-title" tabindex="-1">
<h2 id="hunk-parser-title">Parser: lines 18–31</h2>
<p>2 lines removed, 3 lines added.</p>
<ol class="diff-lines">
<li data-kind="removed"><span class="sr-only">Removed:</span> return null;</li>
<li data-kind="added"><span class="sr-only">Added:</span> throw error;</li>
</ol>
</section>
Do not communicate added and removed lines through red and green alone. Include text labels and visible symbols with accessible names.
Keep controls predictable
Useful controls include:
- next and previous changed hunk;
- expand hidden context;
- copy the current line;
- switch visual layout without changing reading order;
- return focus to the hunk after loading more context.
Avoid stealing ordinary arrow keys from screen readers or text selection. Standard links and buttons already have expected keyboard behavior.
Split view without split semantics
CSS Grid can place old and new cells side by side on wide screens. Keep the DOM grouped by change so each removed/added pair remains adjacent in source order. On narrow screens, collapse to the same unified order.
For unchanged context, do not render thousands of lines and hide them visually. Omit collapsed content from the DOM, announce how many lines are hidden, and insert it only after the user expands the section.
QA matrix
Test at minimum:
| Case | Expected result |
|---|---|
| keyboard only | every hunk reachable; focus remains visible |
| screen reader | change type and code read in logical order |
| 200% zoom | no forced two-dimensional scrolling for core actions |
| color disabled | additions and removals remain distinguishable |
| context loads | focus and hunk heading remain stable |
Accessibility does not require abandoning split view. It requires separating visual layout from semantic order and making the unit of navigation the change a reviewer is trying to understand.
Top comments (0)