React ARIA Widgets
React ARIA Widgets is a collection of React primitives designed to help developers implement the patterns found in the ARIA Authoring Practices Guide (APG).
Please note that this library should NOT be used in a production environment! It's still in a pre-alpha stage and the API is subject to major breaking changes.
Features
- Unstyled, accessible components that are easily composable and customizable
- Modularized design that gives developers the freedom to choose which hooks, components, etc. they wish to import
- Adheres to the APG complete with focus control and keyboard support.
Installation
With npm:
npm install react-aria-widgets
With Yarn:
yarn add react-aria-widgets
Please note that, at the moment, React ARIA Widgets only supports React v18.
Usage
React ARIA Widgets provides building blocks for developers to implement their own component libraries. Though it provides features such as accessibility and state management, that alone is insufficient for it to be used out of the box.
For example, certain patterns rely on styling to handle some of the key features that define that pattern. One instance is the accordion pattern - without styles, expanding/collapsing the constituent sections wouldn't behave properly. However, React ARIA Widgets provides no default styles.
Still, React ARIA Widgets provides state management and aims to maximize compatibility with the variety of CSS libraries, frameworks, etc., in the front-end ecosystem. Building fully working implementations of each pattern can be as simple as passing in some className
props using your framework of choice.
import { Accordion, AccordionItem, AccordionHeader, AccordionPanel } from 'react-aria-widgets/accordion';
export default BasicAccordion() {
return (
<Accordion headerLevel={ 3 }>
<AccordionItem id="item1">
<AccordionHeader>
Accordion Item 1
</AccordionHeader>
<AccordionPanel>
Hello world!
</AccordionPanel>
</AccordionItem>
<AccordionItem id="item2">
<AccordionHeader>
Accordion Item 2
</AccordionHeader>
<AccordionPanel>
Hello world!
</AccordionPanel>
</AccordionItem>
<AccordionItem id="item3">
<AccordionHeader>
Accordion Item 3
</AccordionHeader>
<AccordionPanel>
Hello world!
</AccordionPanel>
</AccordionItem>
</Accordion>
);
}
If you open your browser's developer tools and you click on the buttons, you'll see that the accordion will set the HTML and ARIA attributes correctly. However, other than the default styles that come from your browser and this website's CSS framework, the accordion is completely unstyled, including any styles that should handle collapsing an accordion item when toggled.
React ARIA Widgets aims to be as flexible as possible, and several different styling options are displayed in the following example.
This accordion item is styled by passing in strings for className
and CSS that targets the supplied classes and the state exposed by React ARIA Widgets.
This accordion item is styled by passing in functions for className
. These functions have access to the accordion's state, allowing you to dynamically apply classes.
import { Accordion, AccordionItem, AccordionHeader, AccordionPanel } from 'react-aria-widgets/accordion';
function StyledAccordion() {
return (
<Accordion headerLevel={ 3 }>
<AccordionItem id="item1">
<AccordionHeader>
Accordion Item 1
</AccordionHeader>
<AccordionPanel>
<p>
This accordion item is styled by CSS that targets the default classes provided by React ARIA
Widgets. Since React ARIA Widgets also exposes the accordion's state via HTML data attributes,
we can target selectors such as <code>[data-expanded]</code> or <code>[data-disabled]</code>.
</p>
</AccordionPanel>
</AccordionItem>
<AccordionItem id="item2">
<AccordionHeader
headerProps={{ className: 'custom-accordion-header' }}
buttonProps={{ className: 'custom-accordion-button' }}
>
Accordion Item 2
</AccordionHeader>
<AccordionPanel className="custom-accordion-panel">
<p>
This accordion item is styled by passing in strings for <code>className</code> and
CSS that targets the supplied classes and the state exposed by React ARIA Widgets.
</p>
</AccordionPanel>
</AccordionItem>
<AccordionItem id="item3">
<AccordionHeader
headerProps={{ style: { color: 'hsl(217, 71%, 45%)' } }}
buttonProps={{ style: { color: 'inherit' } }}
>
Accordion Item 3
</AccordionHeader>
<AccordionPanel style={{ color: 'hsl(217, 71%, 45%)' }}>
<p className="mb-4">
This accordion item is styled by passing in objects for <code>style</code>.
</p>
</AccordionPanel>
</AccordionItem>
<AccordionItem id="item4">
<AccordionHeader
headerProps={{ className: ({ isExpanded }) => `another-custom-header ${isExpanded ? 'expanded' : 'collapsed'}` }}
buttonProps={{ className: ({ isExpanded }) => `another-custom-button ${isExpanded ? 'expanded' : 'collapsed'}` }}
>
Accordion Item 4
</AccordionHeader>
<AccordionPanel className={ ({ isExpanded }) => `another-custom-panel ${isExpanded ? 'expanded' : 'collapsed'}` }>
<p>
This accordion item is styled by passing in functions for <code>className</code>. These functions
have access to the accordion's state, allowing you to dynamically apply classes.
</p>
</AccordionPanel>
</AccordionItem>
<AccordionItem id="item5">
<AccordionHeader
headerProps={{ style: ({ isExpanded }) => isExpanded ? { color: 'hsl(0, 0%, 100%)' } : {} }}
buttonProps={{ style: ({ isExpanded }) => isExpanded ? { color: 'inherit', backgroundColor: 'hsl(217, 71%, 53%' } : {} }}
>
Accordion Item 5
</AccordionHeader>
<AccordionPanel style={ ({ isExpanded }) => isExpanded ? {} : { display: 'none' } }>
<p className="mb-4">
This accordion item is styled by passing in functions for <code>style</code>. As before, these
functions allow you to dynamically apply styles based on the accordion's state.
</p>
</AccordionPanel>
</AccordionItem>
<AccordionItem id="item6">
<AccordionHeader>
{ ({ id, getIsExpanded }) => (
<span
className={ getIsExpanded(id) ? 'expanded' : 'collapsed' }
style={ getIsExpanded(id) ? { color: 'hsl(217, 71%, 45%)' } : {} }
>
Accordion Item 6
</span>
) }
</AccordionHeader>
<AccordionPanel>
{ ({ id, getIsExpanded }) => (
<p
className={ getIsExpanded(id) ? 'expanded' : 'collapsed' }
style={ getIsExpanded(id) ? { color: 'hsl(217, 71%, 45%)' } : {} }
>
The content for this accordion item is rendered with a render function. Since these render
functions have access to the accordion's state, you can dynamically style your content.
</p>
) }
</AccordionPanel>
</AccordionItem>
</Accordion>
);
}
.react-aria-widgets-accordion-panel[data-expanded=false] {
display: none;
}
.custom-accordion-panel[data-expanded=false] {
display: none;
}
.another-custom-panel.collapsed {
display: none;
}
In addition to styling options, React ARIA Widgets also provides hooks and other primitives that can be used to build finer-tuned implementations. For more information, see each patterns' individual documentation page.