Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
e7390ef
refactor(data-table): add accessibility and column primitives
oleksandrzavarzin-callstack Aug 26, 2026
40fd57b
feat(button): expose aria-expanded
oleksandrzavarzin-callstack Aug 26, 2026
5e94593
feat(data-table): expose table structure to assistive technology
oleksandrzavarzin-callstack Aug 28, 2026
5909225
fix(data-table): give pagination controls real accessible names
oleksandrzavarzin-callstack Aug 28, 2026
71f79a7
doc(data-table): update migration docs
oleksandrzavarzin-callstack Aug 28, 2026
a91122e
fix(data-table): adress the pr comments
oleksandrzavarzin-callstack Sep 1, 2026
33d651f
fix(data-table): count only real rows and survive fragment children
oleksandrzavarzin-callstack Sep 3, 2026
59302c0
fix(data-table): tell a row component from a wrapper by its type
oleksandrzavarzin-callstack Sep 4, 2026
6d3780c
Merge remote-tracking branch 'upstream/main' into feat/structural-acc…
oleksandrzavarzin-callstack Sep 14, 2026
20bc409
fix(data-table): keep pressable-only props out of the emitted types
oleksandrzavarzin-callstack Sep 14, 2026
607a423
fix(data-table): leave wrapper as written instead of cloning
oleksandrzavarzin-callstack Sep 16, 2026
e53c7ba
Merge remote-tracking branch 'upstream/main' into feat/structural-acc…
oleksandrzavarzin-callstack Sep 16, 2026
c7eebe8
fix(data-table): omit a divider between rows from counting as a row
oleksandrzavarzin-callstack Oct 15, 2026
3c0d158
Merge remote-tracking branch 'upstream/main' into feat/structural-acc…
oleksandrzavarzin-callstack Oct 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 additions & 0 deletions docs/6.x/docs/guides/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,116 @@ const theme = {
/>
```

### DataTable

The Paper 6.x `DataTable` adds table semantics. The structure it produces and the accessible names it exposes have both changed. Existing tables should still be working.

#### Touch handling

Rows, cells and titles with no touch handler render a plain `View` instead of a disabled touchable

```tsx
// Before (v5): announced as a disabled control
<DataTable.Row>
<DataTable.Cell>{item.name}</DataTable.Cell>
</DataTable.Row>

// After (v6): pass a handler if the row is meant to be pressable
<DataTable.Row onPress={() => select(item)}>
<DataTable.Cell>{item.name}</DataTable.Cell>
</DataTable.Row>
```

#### Screen reader announcements

- new `rowCount`, `firstRowIndex` needed for correct row positions when paginating
- `nativeFocusMode="cell"` gives one stop per cell instead of one per row
- `accessible={false}` on a row opts that row out
- `formatRowPosition` replaces the wording, or removes it with `null`
- rows are numbered by their position among the table's rows. A component of your own counts as the one row. A row inside a `View` or a wrapper of your own is counted but not numbered: pass `index` on such a row.

```tsx
// Before (v5)
<DataTable>
{items.slice(from, to).map((item) => (
<DataTable.Row key={item.key}>{/* ... */}</DataTable.Row>
))}
</DataTable>

// After (v6)
<DataTable aria-label="Nutrition" rowCount={items.length} firstRowIndex={from}>
{items.slice(from, to).map((item) => (
<DataTable.Row key={item.key}>{/* ... */}</DataTable.Row>
))}
</DataTable>
```

#### Pagination labels

- `labels` is new, and localizes every control
- `aria-label="pagination-container"` and `aria-label="Options Select"` were removed: reach the controls by role or text, e.g. `getByRole('button', { name: 'Rows per page, 2' })`

```tsx
// After (v6)
<DataTable.Pagination
labels={{
container: 'Paginacja',
previousPage: 'Poprzednia strona',
nextPage: 'Następna strona',
pageStatus: ({ page, numberOfPages }) =>
`Strona ${page} z ${numberOfPages}`,
}}
/* ... */
/>
```

#### Alignment

- `numeric` is unchanged, and now also applies tabular figures
- `align` is new, accepts `'start'`, `'center'`, `'end'`

```tsx
// Before (v5): right-aligned
<DataTable.Cell numeric>{item.calories}</DataTable.Cell>

// After (v6): right-aligned, plus lined-up digits
<DataTable.Cell numeric>{item.calories}</DataTable.Cell>

// Centred, still with lined-up digits
<DataTable.Cell numeric align="center">{item.calories}</DataTable.Cell>

// Right-aligned text that is not numeric
<DataTable.Cell align="end">{item.status}</DataTable.Cell>
```

`align` defaults to `'end'` for numeric columns and `'start'` otherwise.

#### Text wrapping

- **single line, always** → single line at the default font scale, unclamped above it
- `numberOfLines` is honoured exactly at every font scale; pass `0` to never clamp

#### Column definitions

- `columns` on `DataTable` is new and optional
- `column` on a title or cell selects one by key, and is only needed where position is unreliable

```tsx
// Before (v5)
const styles = StyleSheet.create({ first: { flex: 2 } });

<DataTable.Title style={styles.first}>Dessert</DataTable.Title>
<DataTable.Cell style={styles.first}>{item.name}</DataTable.Cell>

// After (v6)
const columns = [{ key: 'name', flex: 2 }, { key: 'calories', numeric: true }];

<DataTable columns={columns}>
<DataTable.Title>Dessert</DataTable.Title>
<DataTable.Cell>{item.name}</DataTable.Cell>
</DataTable>
```

### Card

#### `Card` layout
Expand Down
30 changes: 20 additions & 10 deletions example/src/Examples/DataTableExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as React from 'react';
import { StyleSheet } from 'react-native';

import { DataTable, Card } from 'react-native-paper';
import type { DataTableColumn } from 'react-native-paper';

import ScreenWrapper from '../ScreenWrapper';

Expand All @@ -12,6 +13,14 @@ type ItemsState = Array<{
fat: number;
}>;

// Declared once, outside the component: every title and cell reads its width
// and alignment from here, and the reference has to stay stable.
const columns: readonly DataTableColumn[] = [
{ key: 'name', flex: 2 },
{ key: 'calories', numeric: true },
{ key: 'fat', numeric: true },
];

const DataTableExample = () => {
const [sortAscending, setSortAscending] = React.useState<boolean>(true);
const [page, setPage] = React.useState<number>(0);
Expand Down Expand Up @@ -74,26 +83,30 @@ const DataTableExample = () => {
return (
<ScreenWrapper contentContainerStyle={styles.content}>
<Card>
<DataTable>
<DataTable
aria-label="Nutrition"
columns={columns}
rowCount={sortedItems.length}
firstRowIndex={from}
>
<DataTable.Header>
<DataTable.Title
sortDirection={sortAscending ? 'ascending' : 'descending'}
onPress={() => setSortAscending(!sortAscending)}
style={styles.first}
>
Dessert
</DataTable.Title>
<DataTable.Title numberOfLines={2} numeric>
<DataTable.Title numberOfLines={2}>
Calories per piece
</DataTable.Title>
<DataTable.Title numeric>Fat (g)</DataTable.Title>
<DataTable.Title>Fat (g)</DataTable.Title>
</DataTable.Header>

{sortedItems.slice(from, to).map((item) => (
<DataTable.Row key={item.key}>
<DataTable.Cell style={styles.first}>{item.name}</DataTable.Cell>
<DataTable.Cell numeric>{item.calories}</DataTable.Cell>
<DataTable.Cell numeric>{item.fat}</DataTable.Cell>
<DataTable.Cell>{item.name}</DataTable.Cell>
<DataTable.Cell>{item.calories}</DataTable.Cell>
<DataTable.Cell>{item.fat}</DataTable.Cell>
</DataTable.Row>
))}

Expand All @@ -120,9 +133,6 @@ const styles = StyleSheet.create({
content: {
padding: 8,
},
first: {
flex: 2,
},
});

export default DataTableExample;
7 changes: 7 additions & 0 deletions src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,11 @@ export type Props = Omit<ViewProps, 'style'> & {
* Accessibility role for the button. The "button" role is set by default.
*/
role?: Role;
/**
* Whether the control the button opens is currently expanded. Set this when
* the button anchors a menu or another disclosure.
*/
'aria-expanded'?: boolean;
/**
* Function to execute on press.
*/
Expand Down Expand Up @@ -171,6 +176,7 @@ const Button = ({
textColor: customTextColor,
children,
'aria-label': ariaLabel,
'aria-expanded': ariaExpanded,
accessibilityHint,
role = 'button',
hitSlop,
Expand Down Expand Up @@ -330,6 +336,7 @@ const Button = ({
aria-label={ariaLabel}
accessibilityHint={accessibilityHint}
role={role}
aria-expanded={ariaExpanded}
aria-disabled={disabled}
accessible={accessible}
hitSlop={hitSlop}
Expand Down
Loading
Loading