How to find cross-component accessibility issues
A component may be locally valid but create a semantic problem when its markup is combined with a parent or sibling. This reproducible example uses a repeated id: each TSX file contains one unique id, but the composed page contains two copies of page-title.
Create two files that pass an isolated id check
Create Page.tsx and SummaryPanel.tsx in src. A single-file uniqueIds check sees page-title only once in each file. When Page imports and renders SummaryPanel, the browser receives two elements with the same id and aria-labelledby can resolve ambiguously.
// src/Page.tsx
import { SummaryPanel } from "./SummaryPanel";
export function Page() {
return (
<main aria-labelledby="page-title">
<h1 id="page-title">Dashboard</h1>
<SummaryPanel />
</main>
);
}
// src/SummaryPanel.tsx
export function SummaryPanel() {
return (
<section aria-labelledby="page-title">
<h2 id="page-title">Weekly summary</h2>
</section>
);
}Correct the composed id relationship
Give the panel heading its own id and update the section's aria-labelledby reference. The final component tree now contains two distinct relationships, while the h1 to h2 outline remains sequential.
// src/SummaryPanel.tsx
export function SummaryPanel() {
return (
<section aria-labelledby="summary-title">
<h2 id="summary-title">Weekly summary</h2>
</section>
);
}Reproduce the check in VS Code
Enable cross-component analysis at workspace scope so the extension follows the import from Page.tsx to SummaryPanel.tsx. Saving one file may show local feedback; the workspace scan is the deliberate way to check the composed project graph.
- Add "zemdomu.crossComponentAnalysis": true to .vscode/settings.json.
- Open the repository in VS Code and run ZemDomu: Scan Workspace for Semantic Accessibility Issues.
- Confirm that the duplicate page-title is reported under uniqueIds, apply the corrected id, and rerun the scan.
{
"zemdomu.run": "onSave",
"zemdomu.crossComponentAnalysis": true,
"zemdomu.rules.uniqueIds": true
}Reproduce the same check from the CLI
Run the exact source pattern with cross-component analysis enabled. Checking either file without --cross cannot establish that both copies of page-title appear in the same composed tree.
For a shared command, add "lint:a11y": "zemdomu \"src/**/*.tsx\" --cross --cross-depth 3" to package.json and run npm run lint:a11y before committing.
npm install --save-dev zemdomu
npx zemdomu "src/**/*.tsx" --cross --cross-depth 3Run the identical package script in CI
This complete workflow installs the locked project dependencies and calls the same lint:a11y script used locally. Commit the package script and package-lock.json before pushing the workflow.
name: Cross-component accessibility
on:
pull_request:
permissions:
contents: read
jobs:
zemdomu:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- name: Install dependencies
run: npm ci
- name: Check composed TSX structure
run: npm run lint:a11yInterpret a clean result carefully
Cross-component analysis follows source imports to build more context, but runtime-selected components, generated ids, portals, conditional branches, and server or client rendering differences can change the final DOM. A clear source scan does not prove that every runtime composition is valid.
Inspect the rendered DOM for duplicate ids and accessible-name relationships, then test focus and interaction behavior separately.