How to Check for Accessibility Issues with Astryx Components: Complete CI and Source Validation

Astryx embeds axe-core auditing, mandatory ARIA documentation, and the VisuallyHidden utility directly into its component library, enabling you to check for accessibility issues through automated CI reports, source code inspection, and unit tests.

Checking for accessibility issues with Astryx components requires understanding the framework's integrated validation pipeline. The facebook/astryx repository bakes accessibility (a11y) into every component by exposing ARIA attributes, enforcing required labels through TypeScript, and running axe-core against every Storybook story in the CI pipeline.

Run the Built-in axe-core Audit

The fastest way to check for accessibility issues across your entire Astryx component suite is through the automated audit command. According to the source code in .github/workflows/ci.yml, the CI pipeline executes the pr-a11y job which runs pnpm test:ci --a11y against every Storybook story.

To generate a local accessibility report:


# Install dependencies

pnpm install

# Run the full test suite with axe reporting

pnpm test:ci --a11y

This command generates a11y-report.json, which catalogs violations per component. The audit leverages internal/vibe-tests/src/generate-a11y-manifest.ts to create a manifest of component metadata before scanning. A typical violation entry appears as:

{
  "components": {
    "Button": {
      "violations": [
        {
          "id": "color-contrast",
          "description": "Ensures the contrast ratio is sufficient",
          "nodes": [{ "html": "<button …>" }]
        }
      ]
    }
  }
}

Review Component Documentation for Required A11y Props

Each Astryx component ships with a {Name}.doc.mjs file that explicitly lists required accessibility props. To check for accessibility issues during development, inspect these documentation files to verify you are passing mandatory ARIA attributes.

For example, packages/core/src/TextInput/TextInput.doc.mjs specifies that the label prop is mandatory for accessibility compliance. Omitting it triggers both a TypeScript compile-time error and an axe audit violation:

import {TextInput} from '@astryxdesign/core/TextInput';

// The `label` prop is mandatory for a11y (see TextInput.doc.mjs)
<TextInput label="Username" placeholder="Enter your username" />

Similarly, Button.doc.mjs documents required label or aria-label props to avoid "link-name" violations.

Inspect Source Code for ARIA Patterns

When checking accessibility issues manually, examine the component source files for inline comments that reference axe violations. These comments document specific ARIA patterns and explain implementation choices.

In packages/core/src/Button/Button.tsx at line 693, the source contains explicit references to axe rules:

// disabled controls are removed from the tab order / a11y tree
// (axe: link-name)

This pattern ensures disabled controls do not trigger "link-name" violations by remaining in the accessibility tree while being non-functional.

Leverage the VisuallyHidden Utility

A common accessibility requirement is providing labels for screen readers while hiding them visually. Astryx provides the VisuallyHidden primitive in packages/core/src/VisuallyHidden/VisuallyHidden.tsx to handle this pattern.

The component applies clip-based CSS to hide content visually while ensuring it remains in the accessibility tree. To check for accessibility issues with hidden labels, wrap screen-reader-only text with this utility:

import {VisuallyHidden} from '@astryxdesign/core/VisuallyHidden';

function DeleteButton() {
  return (
    <button type="button" aria-label="Delete">
      <Icon name="trash" />
      {/* Extra label for screen readers, hidden visually */}
      <VisuallyHidden>Delete item</VisuallyHidden>
    </button>
  );
}

The implementation guarantees the element is not rendered with display:none, preserving it for assistive technologies.

Validate with Unit Tests

Astryx components include accessibility assertions in their test suites. To programmatically check for accessibility issues, examine files like packages/core/src/VisuallyHidden/VisuallyHidden.test.tsx, which validates that hidden elements remain discoverable:

// Test validates the element is NOT display:none and is discoverable via getByText
expect(screen.getByText('Delete item')).toBeInTheDocument();

These tests ensure that accessibility patterns, such as the VisuallyHidden clip technique, remain functional across refactors.

Summary

  • Run pnpm test:ci --a11y to generate a11y-report.json and identify axe-core violations across all components via the CI pipeline defined in .github/workflows/ci.yml.
  • Inspect {Component}.doc.mjs files to verify required accessibility props like label and aria-live are implemented.
  • Check source comments in files like Button.tsx for axe violation references (e.g., line 693) that document ARIA implementation patterns.
  • Use <VisuallyHidden> from packages/core/src/VisuallyHidden/VisuallyHidden.tsx when content must be available to screen readers but hidden visually.
  • Review unit tests such as VisuallyHidden.test.tsx to confirm components remain in the accessibility tree and are not using display:none.

Frequently Asked Questions

How do I run accessibility audits locally in Astryx?

Execute pnpm test:ci --a11y from the repository root. This command runs axe-core against every Storybook story and outputs a detailed a11y-report.json file cataloging violations by component ID, matching the behavior of the CI pipeline in .github/workflows/ci.yml.

What is the VisuallyHidden component used for?

VisuallyHidden renders text that is invisible to sighted users but remains accessible to screen readers. Located in packages/core/src/VisuallyHidden/VisuallyHidden.tsx, it uses CSS clipping instead of display:none to keep the element in the accessibility tree, as verified by VisuallyHidden.test.tsx.

Where are accessibility requirements documented for each component?

Each component's accessibility requirements are documented in its corresponding {Name}.doc.mjs file. For example, TextInput.doc.mjs and Button.doc.mjs list required ARIA props, distinguishing between optional and mandatory attributes to prevent "link-name" and labeling violations.

How does Astryx prevent accessibility regressions in CI?

The CI workflow executes internal/vibe-tests/src/generate-a11y-manifest.ts to generate a component manifest before running axe-core against all stories. Any violations are captured in a11y-report.json, and the build fails if critical accessibility standards are not met, ensuring components like Button and TextInput maintain their ARIA patterns.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →