react-native-dialog
Version:
A flexible react-native dialog
275 lines (214 loc) • 12.8 kB
Markdown
# react-native-dialog
[](https://badge.fury.io/js/react-native-dialog)
A flexible pure JavaScript React-Native dialog that follows closely the native UI guidelines.
## Features
- Support for iOS and Android (JavaScript API)
- A flexible declarative API
- Follows closely the UI of native dialogs/alerts
- Can be used both as an alert and as an input prompt
- Can be injected with any component
- Supports light/dark mode
## Demo
<p align="center">
<img src="https://raw.githubusercontent.com/mmazzarolo/react-native-dialog/master/.github/docs-images/react-native-dialog-ios-alert.png" height="500" />
<img src="https://raw.githubusercontent.com/mmazzarolo/react-native-dialog/master/.github/docs-images/react-native-dialog-android-alert.png" height="500" />
</p>
<p align="center">
<img src="https://raw.githubusercontent.com/mmazzarolo/react-native-dialog/master/.github/docs-images/react-native-dialog-ios-input.png" height="500" />
<img src="https://raw.githubusercontent.com/mmazzarolo/react-native-dialog/master/.github/docs-images/react-native-dialog-android-input.png" height="500" />
</p>
## Setup
Install the library using npm or yarn:
```bash
# Using npm:
$ npm install react-native-dialog
# Using yarn:
$ yarn add react-native-dialog
```
## Usage
React-native-dialog exposes a set of components that can be used to build the UI of the dialog:
- **Dialog.Container**: This component is the root component of the dialog and all the other components should be nested inside it.
- **Dialog.Title**: A `Text` component styled as a native dialog title.
- **Dialog.Description**: A `Text` component styled as a native dialog description.
- **Dialog.Button**: A component styled as a native dialog button.
- **Dialog.Input**: A `TextInput` component styled as a native dialog input.
- **Dialog.CodeInput**: A `TextInput` component styled as one time code input.
- **Dialog.Switch**: A native `Switch` component with an optional label.
1. Import react-native-dialog:
```javascript
import Dialog from "react-native-dialog";
```
2. Create a dialog and nest its content inside of it:
```javascript
return (
<View>
<Dialog.Container>
<Dialog.Title>Account delete</Dialog.Title>
<Dialog.Description>
Do you want to delete this account? You cannot undo this action.
</Dialog.Description>
<Dialog.Button label="Cancel" />
<Dialog.Button label="Delete" />
</Dialog.Container>
</View>
);
```
3. Then simply show it by setting the `visible` prop to true:
```javascript
return (
<View>
<Dialog.Container visible={true}>
<Dialog.Title>Account delete</Dialog.Title>
<Dialog.Description>
Do you want to delete this account? You cannot undo this action.
</Dialog.Description>
<Dialog.Button label="Cancel" />
<Dialog.Button label="Delete" />
</Dialog.Container>
</View>
);
```
The `visible` prop is the only prop you'll really need to make the dialog work: you should control this prop value by saving it in your state and setting it to `true` or `false` when needed.
## A complete example
The following example consists in a component (`DialogTester`) with a button and a dialog.
The dialog is controlled by the `dialogVisible` state variable and it is initially hidden since its value is `false`.
Pressing the button sets `dialogVisible` to true, making the dialog visible.
Inside the dialog there are two buttons that, when pressed, set `dialogVisible` to false, hiding the dialog.
```javascript
import React, { useState } from "react";
import { Button, StyleSheet, View } from "react-native";
import Dialog from "react-native-dialog";
export default function App() {
const [visible, setVisible] = useState(false);
const showDialog = () => {
setVisible(true);
};
const handleCancel = () => {
setVisible(false);
};
const handleDelete = () => {
// The user has pressed the "Delete" button, so here you can do your own logic.
// ...Your logic
setVisible(false);
};
return (
<View style={styles.container}>
<Button title="Show dialog" onPress={showDialog} />
<Dialog.Container visible={visible}>
<Dialog.Title>Account delete</Dialog.Title>
<Dialog.Description>
Do you want to delete this account? You cannot undo this action.
</Dialog.Description>
<Dialog.Button label="Cancel" onPress={handleCancel} />
<Dialog.Button label="Delete" onPress={handleDelete} />
</Dialog.Container>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
```
## Available props
### Dialog.Button props
| Name | Type | Default | Description |
| -------- | ------ | -------------------------------------- | --------------------------------------- |
| label | string | **REQUIRED** | The label text |
| color | string | `#007ff9` on iOS, `#169689` on Android | The label color |
| bold | bool | false | Show the label with a bold font weight? |
| disabled | bool | false | Disable the button? |
| onPress | func | **REQUIRED** | Called when the button is pressed |
### Dialog.Description props
| Name | Type | Default | Description |
| -------- | ------ | ------------ | -------------------- |
| children | string | **REQUIRED** | The description text |
### Dialog.Container props
| Name | Type | Default | Description |
| ---------------------- | ------ | ------------- | --------------------------------------------------------------------------------------------------- |
| blurComponentIOS | node | A low-opacity | The blur component used in iOS |
| visible | bool | **REQUIRED** | Show the dialog? |
| children | node | **REQUIRED** | The dialog content |
| contentStyle | any | undefined | Extra style applied to the dialog content |
| headerStyle | any | undefined | Extra style applied to the dialog header |
| footerStyle | any | undefined | Extra style applied to the dialog footer |
| buttonSeparatorStyle | any | undefined | Extra style applied to the dialog button separator |
| onBackdropPress | func | undefined | Callback invoked when the backdrop is pressed |
| onRequestClose | func | undefined | Callback invoked when the hardware back button on Android or the menu button on Apple TV is pressed |
| keyboardVerticalOffset | number | undefined | keyboardVerticalOffset for iOS |
| verticalButtons | bool | false | Renders button vertically |
| useNativeDriver | bool | false | Defines if animations should use native driver |
### Dialog.Input props
| Name | Type | Default | Description |
| ------------------ | ------ | --------- | ----------------------------------------------------------------------- |
| label | string | undefined | The input floating label |
| wrapperStyle | any | undefined | The style applied to the input wrapper View |
| textInputRef | ref | undefined | Ref to the input |
| unstableLabelStyle | any | undefined | Likely to be removed in a future version. See issue #141 for discussion |
`Dialog.Input` also accepts all the React-Native's `TextInput` component props.
### Dialog.CodeInput props
| Name | Type | Default | Description |
| -------------------------- | ------ | --------- | ----------------------------------------------------------- |
| wrapperStyle | any | undefined | The style applied to the input wrapper View |
| digitContainerStyle | any | undefined | The style applied to the digit container View |
| digitContainerFocusedStyle | any | undefined | The style applied to the digit container View when in focus |
| digitStyle | any | undefined | The style applied to the digit text |
| codeLength | number | 4 | The total number of digits |
| onCodeChange | func | undefined | Called when the input changed |
`Dialog.CodeInput` also accepts all the React-Native's `TextInput` component props.
### Dialog.Title props
| Name | Type | Default | Description |
| -------- | ------ | ------------ | -------------- |
| children | string | **REQUIRED** | The title text |
`Dialog.Title` also accepts all the React-Native's `Text` component props.
### Dialog.Switch props
| Name | Type | Default | Description |
| ------------------ | ------ | --------- | ----------------------------------------------------------------------- |
| label | string | undefined | The switch description text |
| unstableLabelStyle | any | undefined | Likely to be removed in a future version. See issue #141 for discussion |
`Dialog.Switch` also accepts all the React-Native's `Switch` component props.
## Frequently Asked Questions
### How can I use a custom blur component as the dialog background on iOS?
To achieve a look even closer to the native iOS dialog you can provide your own component in the `blurComponentIOS` prop of a `Dialog.Container` and it will be injected in the dialog to be used as a background.
The `blurComponentIOS` can be useful for example if you want to apply a native blur effect to the dialog.
Here is an example using `react-native-blur`:
```javascript
const blurComponentIOS = (
<BlurView style={StyleSheet.absoluteFill} blurType="xlight" blurAmount={50} />
);
return (
<View style={styles.container}>
<Dialog.Container visible={visible} blurComponentIOS={blurComponentIOS}>
<Dialog.Title>Account delete</Dialog.Title>
<Dialog.Description>
Do you want to delete this account? You cannot undo this action.
</Dialog.Description>
<Dialog.Button label="Cancel" onPress={handleCancel} />
<Dialog.Button label="Delete" onPress={handleConfirm} />
</Dialog.Container>
</View>
);
```
### How can I add a 'tap outside dialog' callback?
`react-native-dialog` uses [a thin abstraction on top of the React-Native's modal component](./src/Modal.tsx). Any properties you add to `Dialog.Container` are mapped through to the modal.
The modal has an `onBackdropPress` property that can be used to register clicks on the backdrop.
Below is an example of how you can close the dialog by tapping outside.
```javascript
const [visible, setVisible] = useState(true);
const handleCancel = () => {
setVisible(false);
};
return (
<Dialog.Container visible={visible} onBackdropPress={handleCancel}>
<Dialog.Title>Title</Dialog.Title>
<Dialog.Button label="Cancel" onPress={handleCancel} />
</Dialog.Container>
);
```
## Acknowledgments
Thanks to the user [](https://github.com/honaf) who has kindly offered the `react-native-dialog` namespace.
Also thanks to the user [](https://github.com/leecade) who offered the namespace `react-native-alert` (which has not been used since "Dialog" seems to suit better this component) and to [@tyxou](https://github.com/tyxou) for the entire codebase refactoring to hooks.