|
| 1 | +# react-native-resizable-panels |
| 2 | + |
| 3 | +React Native components for resizable panel groups/layouts, using `react-native-reanimated` and `react-native-gesture-handler`. |
| 4 | + |
| 5 | +This library is a port of the popular `react-resizable-panels` for web, and aims to provide the same powerful and flexible API for native applications. |
| 6 | + |
| 7 | +Supported input methods include touch gestures. |
| 8 | + |
| 9 | +--- |
| 10 | + |
| 11 | +This project is a direct translation of the great `react-resizable-panels` library by [Brian Vaughn](https://github.com/bvaughn). All credit for the API design and implementation goes to him. If you find this library useful, please consider supporting the [original project](https://github.com/bvaughn/react-resizable-panels). |
| 12 | + |
| 13 | +--- |
| 14 | + |
| 15 | +## Installation |
| 16 | + |
| 17 | +```bash |
| 18 | +# yarn |
| 19 | +yarn add react-native-resizable-panels react-native-reanimated react-native-gesture-handler |
| 20 | + |
| 21 | +# npm |
| 22 | +npm install react-native-resizable-panels react-native-reanimated react-native-gesture-handler |
| 23 | +``` |
| 24 | + |
| 25 | +You also need to ensure `react-native-reanimated` and `react-native-gesture-handler` are set up correctly. Please follow their respective installation instructions. |
| 26 | + |
| 27 | +## Example App |
| 28 | + |
| 29 | +You can find a comprehensive example app in the `apps/example` directory of this repository. |
| 30 | + |
| 31 | +## Live Examples |
| 32 | + |
| 33 | +- **[Web apр](https://react-native-resizable-panels-example.expo.app/)**: View the example application running in your browser. |
| 34 | +- **Expo Go**: Open the example app on your device using the [Expo Go app](https://expo.dev/go) by scanning the QR code below. |
| 35 | + |
| 36 | +<p align="center"> |
| 37 | + <img src="https://qr.expo.dev/eas-update?slug=exp&projectId=c7e2b6d0-1a80-4771-b8aa-350e3e643e71&groupId=f9426121-c5fa-474c-8d92-8e297f4f5d62&host=u.expo.dev" width="250" height="250" /> |
| 38 | +</p> |
| 39 | + |
| 40 | +## API |
| 41 | + |
| 42 | +### `PanelGroup` |
| 43 | + |
| 44 | +| prop | type | description | |
| 45 | +| ---------- | -------------------------- | ---------------------------------------------------------------- | |
| 46 | +| autoSaveId | ?string | Unique id used to auto-save group arrangement via `AsyncStorage` | |
| 47 | +| children | ReactNode | Arbitrary React element(s) | |
| 48 | +| direction | "horizontal" \| "vertical" | Group orientation | |
| 49 | +| id | ?string | Group id; falls back to `useId` when not provided | |
| 50 | +| onLayout | ?(sizes: number[]) => void | Called when group layout changes | |
| 51 | +| style | ?ViewStyle | Style to attach to root element | |
| 52 | + |
| 53 | +`PanelGroup` components also expose an imperative API for manual resizing: |
| 54 | + |
| 55 | +| method | description | |
| 56 | +| ----------------------- | ---------------------------------------------------------------- | |
| 57 | +| `getId(): string` | Gets the panel group's ID. | |
| 58 | +| `getLayout(): number[]` | Gets the panel group's current _layout_ (\[0 - 100, ...\]). | |
| 59 | +| `setLayout(number[])` | Resize panel group to the specified _layout_ (\[0 - 100, ...\]). | |
| 60 | + |
| 61 | +### `Panel` |
| 62 | + |
| 63 | +| prop | type | description | |
| 64 | +| ------------- | ----------------------- | ----------------------------------------------------------------------------------- | |
| 65 | +| children | ReactNode | Arbitrary React element(s) | |
| 66 | +| collapsedSize | ?number=0 | Panel should collapse to this size | |
| 67 | +| collapsible | ?boolean=false | Panel should collapse when resized beyond its `minSize` | |
| 68 | +| defaultSize | ?number | Initial size of panel (numeric value between 0-100) | |
| 69 | +| id | ?string | Panel id (unique within group); falls back to `useId` when not provided | |
| 70 | +| maxSize | ?number = 100 | Maximum allowable size of panel (numeric value between 0-100) | |
| 71 | +| minSize | ?number = 10 | Minimum allowable size of panel (numeric value between 0-100) | |
| 72 | +| onCollapse | ?() => void | Called when panel is collapsed | |
| 73 | +| onExpand | ?() => void | Called when panel is expanded | |
| 74 | +| onResize | ?(size: number) => void | Called when panel is resized; size parameter is a numeric value between 0-100. | |
| 75 | +| order | ?number | Order of panel within group; required for groups with conditionally rendered panels | |
| 76 | +| style | ?ViewStyle | Style to attach to root element | |
| 77 | + |
| 78 | +`Panel` components also expose an imperative API for manual resizing: |
| 79 | + |
| 80 | +| method | description | |
| 81 | +| ------------------------ | ------------------------------------------------------------------------------ | |
| 82 | +| `collapse()` | If panel is collapsible, collapse it fully. | |
| 83 | +| `expand()` | If panel is currently _collapsed_, expand it to its most recent size. | |
| 84 | +| `getId(): string` | Gets the ID of the panel. | |
| 85 | +| `getSize(): number` | Gets the current size of the panel as a percentage (0 - 100). | |
| 86 | +| `isCollapsed(): boolean` | Returns true if the panel is currently _collapsed_ (size === `collapsedSize`). | |
| 87 | +| `isExpanded(): boolean` | Returns true if the panel is currently _not collapsed_ (`!isCollapsed()`). | |
| 88 | +| `resize(size: number)` | Resize panel to the specified _percentage_ (0 - 100). | |
| 89 | + |
| 90 | +### `PanelResizeHandle` |
| 91 | + |
| 92 | +| prop | type | description | |
| 93 | +| ---------- | ------------------------------ | ----------------------------------------------------- | |
| 94 | +| children | ?ReactNode | Custom drag UI; can be any arbitrary React element(s) | |
| 95 | +| disabled | ?boolean | Disable drag handle | |
| 96 | +| id | ?string | Resize handle id (unique within group) | |
| 97 | +| onDragging | ?(isDragging: boolean) => void | Called when group layout changes | |
| 98 | +| style | ?ViewStyle | Style to attach to root element | |
| 99 | + |
| 100 | +## FAQ |
| 101 | + |
| 102 | +### Can panel sizes be specified in pixels? |
| 103 | + |
| 104 | +No. Pixel-based constraints added significant complexity to the initialization and validation logic and so they are not supported. |
| 105 | + |
| 106 | +### How can I fix layout/sizing problems with conditionally rendered panels? |
| 107 | + |
| 108 | +The `Panel` API doesn't _require_ `id` and `order` props because they aren't necessary for static layouts. When panels are conditionally rendered though, it's best to supply these values. |
| 109 | + |
| 110 | +```tsx |
| 111 | +import { Panel, PanelGroup, PanelResizeHandle } from 'react-native-resizable-panels'; |
| 112 | + |
| 113 | +<PanelGroup direction="horizontal"> |
| 114 | + {renderSideBar && ( |
| 115 | + <> |
| 116 | + <Panel id="sidebar" minSize={25} order={1}> |
| 117 | + <Sidebar /> |
| 118 | + </Panel> |
| 119 | + <PanelResizeHandle /> |
| 120 | + </> |
| 121 | + )} |
| 122 | + <Panel minSize={25} order={2}> |
| 123 | + <Main /> |
| 124 | + </Panel> |
| 125 | +</PanelGroup>; |
| 126 | +``` |
| 127 | + |
| 128 | +### Why don't I see any resize UI? |
| 129 | + |
| 130 | +This likely means that you haven't applied any styling to the resize handles. By default, a resize handle is just an empty `View`. To add styling, use the `style` prop: |
| 131 | + |
| 132 | +```tsx |
| 133 | +import { PanelResizeHandle } from 'react-native-resizable-panels'; |
| 134 | +import { StyleSheet } from 'react-native'; |
| 135 | + |
| 136 | +<PanelResizeHandle style={styles.resizeHandle} />; |
| 137 | + |
| 138 | +const styles = StyleSheet.create({ |
| 139 | + resizeHandle: { |
| 140 | + width: 4, |
| 141 | + backgroundColor: '#888888', |
| 142 | + }, |
| 143 | +}); |
| 144 | +``` |
| 145 | + |
| 146 | +### Can panel sizes be persistent? |
| 147 | + |
| 148 | +Yes. Panel groups with an `autoSaveId` prop will automatically save and restore their layouts on mount using `AsyncStorage`. |
0 commit comments