React Aria is a library of unstyled, accessible hooks from Adobe. It handles keyboard navigation, screen readers, focus management, and internationalization — you handle the styling.
Why React Aria?
- 100% accessible — WCAG 2.1 AA compliant out of the box
- Unstyled — hooks, not components — style however you want
- Internationalization — 30+ languages, RTL, date/number formatting
- Keyboard/touch — handles all interaction modes correctly
Quick Start
npm install react-aria-components
Pre-Built Components (react-aria-components)
import { Button, TextField, Label, Input, Select, SelectValue, Popover, ListBox, ListBoxItem } from 'react-aria-components';
function MyForm() {
return (
<form>
<TextField>
<Label>Email</Label>
<Input type="email" />
</TextField>
<Select>
<Label>Role</Label>
<Button><SelectValue /></Button>
<Popover>
<ListBox>
<ListBoxItem>Admin</ListBoxItem>
<ListBoxItem>User</ListBoxItem>
<ListBoxItem>Guest</ListBoxItem>
</ListBox>
</Popover>
</Select>
<Button type="submit">Submit</Button>
</form>
);
}
Hooks (Low-Level)
import { useButton } from 'react-aria';
import { useRef } from 'react';
function MyButton(props) {
const ref = useRef(null);
const { buttonProps } = useButton(props, ref);
return (
<button {...buttonProps} ref={ref} className="my-button">
{props.children}
</button>
);
}
Dialog/Modal
import { DialogTrigger, Modal, Dialog, Heading } from 'react-aria-components';
function MyDialog() {
return (
<DialogTrigger>
<Button>Open Dialog</Button>
<Modal>
<Dialog>
<Heading slot="title">Confirm</Heading>
<p>Are you sure?</p>
<Button slot="close">Cancel</Button>
<Button>Confirm</Button>
</Dialog>
</Modal>
</DialogTrigger>
);
}
Table
import { Table, TableHeader, Column, TableBody, Row, Cell } from 'react-aria-components';
function UserTable({ users }) {
return (
<Table aria-label="Users" selectionMode="multiple">
<TableHeader>
<Column isRowHeader>Name</Column>
<Column>Email</Column>
<Column>Role</Column>
</TableHeader>
<TableBody>
{users.map(user => (
<Row key={user.id}>
<Cell>{user.name}</Cell>
<Cell>{user.email}</Cell>
<Cell>{user.role}</Cell>
</Row>
))}
</TableBody>
</Table>
);
}
Date Picker
import { DatePicker, Label, Group, DateInput, DateSegment, Button, Popover, Dialog, Calendar, CalendarGrid, CalendarCell } from 'react-aria-components';
function MyDatePicker() {
return (
<DatePicker>
<Label>Date</Label>
<Group>
<DateInput>{(segment) => <DateSegment segment={segment} />}</DateInput>
<Button>Open</Button>
</Group>
<Popover>
<Dialog>
<Calendar>
<CalendarGrid>
{(date) => <CalendarCell date={date} />}
</CalendarGrid>
</Calendar>
</Dialog>
</Popover>
</DatePicker>
);
}
Building accessible data apps? Check out my Apify actors for web scraping, or email spinov001@gmail.com for accessible React solutions.
React Aria, Radix UI, or Headless UI — which accessible library do you use? Share below!
Top comments (0)