Skip to content

About components the scanner can and cannot see

Accessibility rules are written about HTML elements — button, input, a, label, img. Almost nobody writes those directly any more. You write <Button>, <TextField>, <Checkbox>, and the element only appears somewhere inside. For a rule like “every input needs an accessible name” to fire on your code, the scanner has to work out which of your components is an input.

This page is about how it works that out, and what happens when it cannot — which is the usual reason a finding you expected does not appear.

b8e tries four things, in order, and stops at the first that gives a confident answer.

  1. Your declaration. If you have mapped a component in binclusive.json, that wins over everything else. See Declare a component the scanner can’t resolve.
  2. The built-in registry. Common design systems — Radix, MUI, and others — are mapped already. Radix Label.Root is a label; MUI TextField is an input. Only components with one unambiguous element are listed: layout and container components like Card or a dialog wrapper are left out, because calling them any single element would be wrong.
  3. Reading your component. For anything the registry does not know, the scanner opens the component’s own source, using your real tsconfig paths and aliases, and asks whether it renders exactly one element and forwards its props. If both hold, it has its answer. This is what lets scanning work on your codebase with no configuration at all.
  4. Following the import graph. Barrel files, re-exports, and long forwarding chains lose the trail in step 3. When the project resolves, the scanner follows the export back through the real import graph to the module where the element actually lives.

If none of those give a confident answer, the component is reported as unresolved rather than guessed at.

That is the trade worth knowing about: a real defect inside a component the scanner cannot see will not be reported by the source scan. The run tells you which components it could not resolve, so you know where the gaps are.

You have two ways to close the gap:

  • Declare it. Map the component to its element in binclusive.json and every rule for that element starts firing on it. b8e init --suggest will pre-fill declarations from the scanner’s best guesses for you to review.
  • Scan the rendered page instead. A component whose element is only decided at runtime is exactly what b8e scan --url and the other live-DOM lanes are for. See About the two scanning models.

Following the import graph needs a resolvable project. On a cold checkout or a shallow CI clone with no reachable tsconfig, that step is skipped and the first three still run — you keep declaration, registry, and single-file tracing, and lose only the extra reach the graph would have added.