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

> Discover how to check for accessibility issues with Astryx components using automated CI reports, source code inspection, and unit tests. Integrate axe-core for robust validation.

- Repository: [Meta/astryx](https://github.com/facebook/astryx)
- Tags: how-to-guide
- Published: 2026-07-15

---

**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`](https://github.com/facebook/astryx/blob/main/.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:

```bash

# Install dependencies

pnpm install

# Run the full test suite with axe reporting

pnpm test:ci --a11y

```

This command generates [`a11y-report.json`](https://github.com/facebook/astryx/blob/main/a11y-report.json), which catalogs violations per component. The audit leverages [`internal/vibe-tests/src/generate-a11y-manifest.ts`](https://github.com/facebook/astryx/blob/main/internal/vibe-tests/src/generate-a11y-manifest.ts) to create a manifest of component metadata before scanning. A typical violation entry appears as:

```json
{
  "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:

```tsx
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`](https://github.com/facebook/astryx/blob/main/packages/core/src/Button/Button.tsx) at line 693, the source contains explicit references to axe rules:

```tsx
// 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`](https://github.com/facebook/astryx/blob/main/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:

```tsx
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`](https://github.com/facebook/astryx/blob/main/packages/core/src/VisuallyHidden/VisuallyHidden.test.tsx), which validates that hidden elements remain discoverable:

```tsx
// 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`](https://github.com/facebook/astryx/blob/main/a11y-report.json) and identify axe-core violations across all components via the CI pipeline defined in [`.github/workflows/ci.yml`](https://github.com/facebook/astryx/blob/main/.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`](https://github.com/facebook/astryx/blob/main/Button.tsx) for axe violation references (e.g., line 693) that document ARIA implementation patterns.
- **Use `<VisuallyHidden>`** from [`packages/core/src/VisuallyHidden/VisuallyHidden.tsx`](https://github.com/facebook/astryx/blob/main/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`](https://github.com/facebook/astryx/blob/main/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`](https://github.com/facebook/astryx/blob/main/a11y-report.json) file cataloging violations by component ID, matching the behavior of the CI pipeline in [`.github/workflows/ci.yml`](https://github.com/facebook/astryx/blob/main/.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`](https://github.com/facebook/astryx/blob/main/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`](https://github.com/facebook/astryx/blob/main/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`](https://github.com/facebook/astryx/blob/main/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`](https://github.com/facebook/astryx/blob/main/a11y-report.json), and the build fails if critical accessibility standards are not met, ensuring components like `Button` and `TextInput` maintain their ARIA patterns.