How to Implement Accessibility in Astryx Components: Patterns and Best Practices
Astryx components implement accessibility through semantic ARIA attributes, a dedicated VisuallyHidden primitive for screen-reader-only content, and comprehensive unit testing that validates ARIA roles and properties.
Implementing accessibility in Astryx components follows a systematic approach built into the facebook/astryx repository. The component library embeds inclusive design patterns directly into its core architecture, ensuring that interactive elements work seamlessly with assistive technologies without requiring additional configuration.
Core Accessibility Architecture
Semantic ARIA Roles and Attributes
Every interactive element in Astryx includes appropriate ARIA roles such as button, status, and dialog, along with attributes like aria-label, aria-labelledby, aria-describedby, aria-live, aria-expanded, and aria-current. These properties are defined in component JSX within files like packages/core/src/Button/Button.tsx and propagated directly to the DOM.
The VisuallyHidden Primitive
The VisuallyHidden component located in packages/core/src/VisuallyHidden/VisuallyHidden.tsx provides a styling-free container that renders text off-screen while remaining accessible to assistive technology. It supports polymorphic rendering via the as prop, allowing it to function as any HTML element. This primitive is essential for:
- Descriptive labels on inputs and buttons
- Live region announcements
- Accessibility-only descriptions for icon-only controls
Implementing Accessible Patterns
Labeling Inputs with VisuallyHidden
When building forms, associate labels with inputs using unique IDs and aria-labelledby. The TextInput component in packages/core/src/TextInput/TextInput.tsx follows this pattern:
import {TextInput} from '@astryxdesign/core/TextInput';
import {VisuallyHidden} from '@astryxdesign/core/VisuallyHidden';
function EmailField() {
const inputLabelID = 'email-label';
return (
<>
<VisuallyHidden id={inputLabelID}>Email address</VisuallyHidden>
<TextInput
id="email"
aria-labelledby={inputLabelID}
placeholder="you@example.com"
/>
</>
);
}
Live Region Announcements
Use VisuallyHidden with aria-live to announce status changes without visual disruption:
import {VisuallyHidden} from '@astryxdesign/core/VisuallyHidden';
function LoadingSpinner() {
return (
<div role="status">
<Spinner size="md" />
<VisuallyHidden aria-live="polite">Loading data</VisuallyHidden>
</div>
);
}
Multi-Step Navigation with aria-current
The Stepper component in packages/lab/src/Stepper/Stepper.tsx demonstrates advanced accessibility patterns:
import {Stepper} from '@astryxdesign/lab/Stepper';
<Stepper
steps={['Step 1', 'Step 2', 'Step 3']}
currentStep={1}
aria-label="Progress through wizard"
/>
Internally, each step renders aria-current="step" on the active item and uses VisuallyHidden for descriptive labels.
Keyboard Navigation and Focus Management
Components such as Button, Switch, Drawer, and Stepper ensure logical focus order by exposing native HTML elements whenever possible. In packages/core/src/Button/Button.tsx and packages/lab/src/Drawer/Drawer.tsx, refs are forwarded to maintain programmatic focus control. This allows developers to manage focus shifts during interactions like opening modals or navigating between steps.
Automated Accessibility Testing
Astryx enforces accessibility through unit tests that assert the presence and correctness of ARIA attributes. Tests validate patterns such as expect(screen.getByRole('dialog')).toHaveAttribute('aria-modal', 'true') in component test files like packages/core/src/Button/Button.test.tsx and packages/lab/src/Drawer/Drawer.test.tsx. This testing strategy prevents regressions in screen reader compatibility.
Summary
- Astryx embeds accessibility through semantic ARIA roles and attributes defined in component JSX
- The
VisuallyHiddenprimitive inpackages/core/src/VisuallyHidden/VisuallyHidden.tsxenables screen-reader-only content without visual impact - Keyboard navigation relies on native HTML elements and ref forwarding in components like
ButtonandDrawer - Unique ID generation pairs labels with controls via
aria-labelledbyandaria-describedby - Unit tests in
*.test.tsxfiles validate ARIA attributes to prevent accessibility regressions
Frequently Asked Questions
What ARIA attributes does Astryx support?
Astryx components support standard ARIA attributes including aria-label, aria-labelledby, aria-describedby, aria-live, aria-expanded, aria-current, and role definitions such as button, status, and dialog. These are implemented in the component source files and propagated directly to the DOM.
How does the VisuallyHidden component work?
The VisuallyHidden component renders content off-screen using CSS while keeping it in the accessibility tree. Located in packages/core/src/VisuallyHidden/VisuallyHidden.tsx, it accepts an as prop for polymorphic rendering and is used throughout the library for labels, live regions, and icon descriptions.
Does Astryx handle focus management automatically?
Yes, components like Button, Switch, Drawer, and Stepper manage focus through native HTML elements and ref forwarding. This pattern, visible in packages/core/src/Button/Button.tsx and packages/lab/src/Drawer/Drawer.tsx, ensures logical tab order and programmatic focus control.
How are accessibility features tested in Astryx?
Each component includes unit tests that verify ARIA attributes using assertions like toHaveAttribute. Test files such as packages/core/src/TextInput/TextInput.test.tsx and packages/lab/src/Stepper/Stepper.test.tsx ensure that accessibility properties remain intact across updates.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →