Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion docs/6.x/docs/components/Drawer/DrawerItem.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export default MyComponent;

## Theme colors

<ThemeColorsTable themeColorsData={{"active":{"backgroundColor":"theme.colors.secondaryContainer","iconColor/textColor":"theme.colors.onSecondaryContainer"},"inactive":{"iconColor/textColor":"theme.colors.onSurfaceVariant"}}} componentName="Drawer.Item" />
<ThemeColorsTable themeColorsData={{"active":{"backgroundColor":"theme.colors.secondaryContainer","iconColor/textColor":"theme.colors.onSecondaryContainer"},"inactive":{"iconColor/textColor":"theme.colors.onSurfaceVariant"},"focused":{"focusIndicatorColor":"theme.colors.secondary"}}} componentName="Drawer.Item" />


<span />
2 changes: 1 addition & 1 deletion docs/6.x/docs/components/Drawer/DrawerSection.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export default MyComponent;

## Theme colors

<ThemeColorsTable themeColorsData={{"-":{"titleColor":"theme.colors.onSurfaceVariant"}}} componentName="Drawer.Section" />
<ThemeColorsTable themeColorsData={{"-":{"titleColor":"theme.colors.onSurfaceVariant","dividerColor":"theme.colors.outlineVariant"}}} componentName="Drawer.Section" />


<span />
17 changes: 17 additions & 0 deletions docs/6.x/docs/guides/migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,23 @@ TBC

## Components

### Drawer

The `Drawer` API is unchanged in Paper 6.x — no props were renamed, removed, or given new defaults. `Drawer.Item` and `Drawer.Section` were realigned with the current Material Design 3 navigation drawer spec, so their appearance changes:

- **Trailing padding.** `Drawer.Item` reserved 36dp on the trailing edge and 28dp on the leading edge. Both are now 28dp, as the spec requires. Items sit 8dp wider.

@satya164 satya164 Oct 22, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Items sit 8dp wider" is not what changed. The active indicator keeps its size: 12dp from each drawer edge on main and in this PR (336dp wide in a 360dp drawer). Only the content area grows by 8dp on the trailing side, so long labels truncate later and the right content moves 8dp toward the edge.

Suggested change
- **Trailing padding.** `Drawer.Item` reserved 36dp on the trailing edge and 28dp on the leading edge. Both are now 28dp, as the spec requires. Items sit 8dp wider.
- **Trailing padding.** `Drawer.Item` reserved 36dp between the drawer edge and its content on the trailing side, and 28dp on the leading side. Both are now 28dp, as the spec requires. The active indicator keeps its size. The label and the `right` content get 8dp more room.

(via Claude, verify if it makes sense)

- **Active label weight.** The label of an active `Drawer.Item` now uses the prominent `labelLargeEmphasized` weight (700). Inactive labels are unchanged at 500.
- **Section divider colour.** `Drawer.Section` drew its divider in a fixed grey that ignored the theme and was wrong in dark mode. It now uses `theme.colors.outlineVariant`, like every other `Divider`.
- **Focus indicator.** `Drawer.Item` gains a keyboard focus ring in `theme.colors.secondary`. It appears only on keyboard focus, not on press.

@satya164 satya164 Oct 22, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The list leaves out the disabled change. A disabled Drawer.Item or Drawer.CollapsedItem is now drawn at 38% opacity, while in 5.x it looked the same as an enabled item. Anyone who passes disabled sees a different drawer after the upgrade.

Suggested change
- **Focus indicator.** `Drawer.Item` gains a keyboard focus ring in `theme.colors.secondary`. It appears only on keyboard focus, not on press.
- **Focus indicator.** `Drawer.Item` gains a keyboard focus ring in `theme.colors.secondary`. It appears only on keyboard focus, not on press.
- **Disabled state.** Disabled `Drawer.Item` and `Drawer.CollapsedItem` destinations are now dimmed to 38% opacity. In 5.x they looked the same as enabled ones.

(via Claude, verify if it makes sense)


If you were pixel-matching a drawer against Paper 5.x, the first two points are the ones that will shift your layout. To restore the old trailing padding, pass it through `style`:

```tsx
<Drawer.Item label="Inbox" icon="inbox" style={{ marginEnd: 20 }} />
```
Comment on lines +18 to +22

@satya164 satya164 Oct 22, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This snippet does not restore the 5.x layout. style goes to the active indicator container, so marginEnd: 20 moves the indicator edge, not the content. With this snippet on web, the indicator ends 20dp from the drawer edge and is 328dp wide instead of 336dp. The content does end 36dp from the edge, but an active item now has a visibly shorter indicator than in 5.x. There is no prop that changes only the content inset, so I suggest dropping the workaround:

Suggested change
If you were pixel-matching a drawer against Paper 5.x, the first two points are the ones that will shift your layout. To restore the old trailing padding, pass it through `style`:
```tsx
<Drawer.Item label="Inbox" icon="inbox" style={{ marginEnd: 20 }} />
```
If you were pixel-matching a drawer against Paper 5.x, the first two points are the ones that will shift your layout.

(via Claude, verify if it makes sense)


The theme also gains the 15 `*Emphasized` typescale keys (`labelLargeEmphasized`, `titleSmallEmphasized`, and so on). The values already existed in the token set; only the types were missing, so `<Text variant="labelLargeEmphasized">` now typechecks. This is additive — no existing key changed.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two problems with this paragraph:

  1. It is not fully additive. Theme['fonts'] is Typescale, which is Record<TypescaleKey, TypescaleStyle>. A theme that sets fonts to a hand-written object with the 15 base variants and default now fails to typecheck, because the 15 emphasized keys are required. Say that here, so people with a hand-written fonts object know to spread MD3LightTheme.fonts or use configureFonts.
  2. These keys are now public Text variants, but the Fonts guide (docs/6.x/docs/guides/fonts.md) still lists only the base variants. Add the emphasized variants there, so people can find them. (via Claude, verify if it makes sense)


### TextInput

The Paper 6.x `TextInput` is a complete rewrite with a new API. Import the component the same way, but note that the props and behavior have changed significantly.
Expand Down
Binary file modified docs/public/screenshots/drawer-item.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/public/screenshots/drawer-section.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions docs/src/data/componentDocs6x.json
Original file line number Diff line number Diff line change
Expand Up @@ -5646,7 +5646,7 @@
"tsType": {
"name": "boolean"
},
"description": "Whether the item is disabled."
"description": "Whether the item is disabled. Disabled items are dimmed and don't respond to touch."
},
"focusedIcon": {
"required": false,
Expand Down Expand Up @@ -5781,7 +5781,7 @@
"tsType": {
"name": "boolean"
},
"description": "Whether the item is disabled."
"description": "Whether the item is disabled. Disabled items are dimmed and don't respond to touch."
},
"onPress": {
"required": false,
Expand Down
5 changes: 5 additions & 0 deletions docs/src/data/themeColors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,10 +140,15 @@ export const themeColors = {
inactive: {
'iconColor/textColor': 'theme.colors.onSurfaceVariant',
},
focused: {
focusIndicatorColor: 'theme.colors.secondary',
'iconColor/textColor (inactive)': 'theme.colors.onSurface',
},
},
'Drawer.Section': {
'-': {
titleColor: 'theme.colors.onSurfaceVariant',
dividerColor: 'theme.colors.outlineVariant',
},
},
FAB: {
Expand Down
19 changes: 7 additions & 12 deletions example/src/DrawerItems.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,10 @@ function DrawerItems() {

return (
<DrawerContentScrollView
alwaysBounceVertical={false}
style={[
styles.drawerContent,
{
backgroundColor: colors.surface,
backgroundColor: colors.surfaceContainerLow,
},
]}
>
Expand Down Expand Up @@ -175,7 +174,7 @@ function DrawerItems() {
<Drawer.Section title="Preferences">
{dynamicThemeSupported ? (
<TouchableRipple onPress={toggleShouldUseDynamicTheme}>
<View style={[styles.preference, styles.v3Preference]}>
<View style={styles.preference}>
<Text variant="labelLarge">Use Dynamic Theme</Text>
<View pointerEvents="none">
<Switch value={shouldUseDynamicTheme} />
Expand All @@ -184,7 +183,7 @@ function DrawerItems() {
</TouchableRipple>
) : null}
<TouchableRipple onPress={toggleTheme}>
<View style={[styles.preference, styles.v3Preference]}>
<View style={styles.preference}>
<Text variant="labelLarge">Dark Theme</Text>
<View pointerEvents="none">
<Switch value={isDarkTheme} />
Expand All @@ -193,7 +192,7 @@ function DrawerItems() {
</TouchableRipple>

<TouchableRipple onPress={_handleToggleRTL}>
<View style={[styles.preference, styles.v3Preference]}>
<View style={styles.preference}>
<Text variant="labelLarge">RTL</Text>
<View pointerEvents="none">
<Switch value={isRTL} />
Expand All @@ -202,7 +201,7 @@ function DrawerItems() {
</TouchableRipple>

<TouchableRipple onPress={toggleCollapsed}>
<View style={[styles.preference, styles.v3Preference]}>
<View style={styles.preference}>
<Text variant="labelLarge">Collapsed drawer *</Text>
<View pointerEvents="none">
<Switch value={collapsed} />
Expand All @@ -211,7 +210,7 @@ function DrawerItems() {
</TouchableRipple>

<TouchableRipple onPress={toggleCustomFont}>
<View style={[styles.preference, styles.v3Preference]}>
<View style={styles.preference}>
<Text variant="labelLarge">Custom font *</Text>
<View pointerEvents="none">
<Switch value={customFontLoaded} />
Expand All @@ -220,7 +219,7 @@ function DrawerItems() {
</TouchableRipple>

<TouchableRipple onPress={toggleRippleEffect}>
<View style={[styles.preference, styles.v3Preference]}>
<View style={styles.preference}>
<Text variant="labelLarge">
{isIOS ? 'Highlight' : 'Ripple'} effect *
</Text>
Expand Down Expand Up @@ -271,10 +270,6 @@ const styles = StyleSheet.create({
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
paddingVertical: 12,
paddingHorizontal: 16,
},
v3Preference: {
height: 56,
paddingHorizontal: 28,
},
Expand Down
2 changes: 2 additions & 0 deletions example/src/ExampleList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import ChipExample from './Examples/ChipExample';
import DataTableExample from './Examples/DataTableExample';
import DialogExample from './Examples/DialogExample';
import DividerExample from './Examples/DividerExample';
import DrawerExample from './Examples/DrawerExample';
import FABExample from './Examples/FABExample';
import IconButtonExample from './Examples/IconButtonExample';
import IconExample from './Examples/IconExample';
Expand Down Expand Up @@ -64,6 +65,7 @@ export const mainExamples = {
DataTable: DataTableExample,
Dialog: DialogExample,
Divider: DividerExample,
Drawer: DrawerExample,
FAB: FABExample,
IconButton: IconButtonExample,
Icon: IconExample,
Expand Down
196 changes: 196 additions & 0 deletions example/src/Examples/DrawerExample.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
import * as React from 'react';
import { StyleSheet, View } from 'react-native';
import type { ColorValue } from 'react-native';

import { Badge, Drawer, Text, useTheme } from 'react-native-paper';

import ScreenWrapper from '../ScreenWrapper';

const DRAWER_WIDTH = 360;

const Section = ({
title,
children,
}: {
title: string;
children: React.ReactNode;
}) => {
const theme = useTheme();

return (
<View style={styles.section}>
<Text
variant="labelSmall"
style={[styles.caption, { color: theme.colors.onSurfaceVariant }]}
>
{title}
</Text>
<View
style={[
styles.drawer,
{ backgroundColor: theme.colors.surfaceContainerLow },
]}
>
{children}
</View>
</View>
);
};

const Destinations = () => {
const [active, setActive] = React.useState('inbox');

return (
<Drawer.Section title="Mail" showDivider={false}>
<Drawer.Item
icon="inbox"
label="Inbox"
active={active === 'inbox'}
onPress={() => setActive('inbox')}
right={() => <Text variant="labelLarge">24</Text>}
/>
<Drawer.Item
icon="star"
label="Starred"
active={active === 'starred'}
onPress={() => setActive('starred')}
/>
<Drawer.Item
icon="send"
label="Sent"
active={active === 'sent'}
onPress={() => setActive('sent')}
/>
</Drawer.Section>
);
};

const DrawerExample = () => {
const [collapsed, setCollapsed] = React.useState('inbox');

return (
<ScreenWrapper contentContainerStyle={styles.content}>
<Section title="Destinations — tap to change the active one">
<Destinations />
</Section>

<Section title="Without an icon, and with a truncated label">
<Drawer.Section showDivider={false}>
<Drawer.Item label="No icon" />
<Drawer.Item
icon="delete"
label="A very long destination label that will be truncated"
/>
</Drawer.Section>
</Section>

<Section title="Disabled">
<Drawer.Section showDivider={false}>
<Drawer.Item icon="archive" label="Archive" disabled />
<Drawer.Item
icon="star"
label="Active and disabled"
active
disabled
right={() => <Text variant="labelLarge">24</Text>}
/>
</Drawer.Section>
</Section>

<Section title="Trailing slot">
<Drawer.Section showDivider={false}>
<Drawer.Item
icon="alert"
label="Badge"
right={() => <Badge visible style={styles.badge} />}
/>
<Drawer.Item
icon="palette"
label="Coloured dot"
right={({ color }: { color: ColorValue }) => (
<Badge
visible
style={[styles.badge, { backgroundColor: color }]}
/>
)}
/>
</Drawer.Section>
</Section>

<Section title="Sections separated by a divider">
<Drawer.Section title="Mailboxes">
<Drawer.Item icon="inbox" label="Inbox" />
</Drawer.Section>
<Drawer.Section title="Labels" showDivider={false}>
<Drawer.Item icon="tag" label="Work" />
</Drawer.Section>
</Section>

<Section title="Collapsed destinations">
<View style={styles.collapsed}>
<Drawer.CollapsedItem
focusedIcon="inbox"
unfocusedIcon="inbox-outline"
label="Inbox"
badge={24}
active={collapsed === 'inbox'}
onPress={() => setCollapsed('inbox')}
/>
<Drawer.CollapsedItem
focusedIcon="star"
unfocusedIcon="star-outline"
label="Starred"
active={collapsed === 'starred'}
onPress={() => setCollapsed('starred')}
/>
<Drawer.CollapsedItem
focusedIcon="bell"
unfocusedIcon="bell-outline"
badge
active={collapsed === 'alerts'}
onPress={() => setCollapsed('alerts')}
/>
Comment on lines +146 to +152

@satya164 satya164 Oct 22, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This item has no label and no aria-label, so it is a button with no accessible name. The iOS accessibility tree shows an unnamed button, and on web the button has no aria-label and only the icon glyph as text. A screen reader user cannot tell what it does. Since the example is what people copy, give it a name:

Suggested change
<Drawer.CollapsedItem
focusedIcon="bell"
unfocusedIcon="bell-outline"
badge
active={collapsed === 'alerts'}
onPress={() => setCollapsed('alerts')}
/>
<Drawer.CollapsedItem
focusedIcon="bell"
unfocusedIcon="bell-outline"
badge
aria-label="Alerts"
active={collapsed === 'alerts'}
onPress={() => setCollapsed('alerts')}
/>

(via Claude, verify if it makes sense)

<Drawer.CollapsedItem
focusedIcon="archive"
unfocusedIcon="archive-outline"
label="Disabled"
disabled
/>
</View>
</Section>
</ScreenWrapper>
);
};

DrawerExample.title = 'Drawer';

const styles = StyleSheet.create({
content: {
paddingVertical: 16,
},
section: {
marginBottom: 24,
},
caption: {
marginBottom: 8,
marginHorizontal: 16,
},
drawer: {
width: DRAWER_WIDTH,
maxWidth: '100%',
alignSelf: 'center',
paddingVertical: 8,
borderTopEndRadius: 16,
borderBottomEndRadius: 16,
},
badge: {
alignSelf: 'center',
},
collapsed: {
flexDirection: 'row',
justifyContent: 'center',
paddingVertical: 8,
},
});

export default DrawerExample;
Loading