Modal (Dialog)
Installation
To get started, install Headless UI via npm:
npm install headlessui-react-native
Basic example
Modals are built using the Modal
, ModalPanel
, and ModalTitle
components:
import { Modal, ModalPanel, ModalTitle } from "headlessui-react-native";
import React, { useState } from "react";
import { Button, Text, TextStyle, View, ViewStyle } from "react-native";
export function ModalExample() {
const [isOpen, setIsOpen] = useState(false);
return (
<View>
<Button title="Open dialog" onPress={() => setIsOpen(true)} />
<Modal onClose={() => setIsOpen(false)} open={isOpen}>
<View style={modalContainerStyle}>
<ModalPanel style={modalPanelStyle}>
<ModalTitle style={modalTitleStyle}>Payment successful</ModalTitle>
<View style={modalPanelContentStyle}>
<Text>
Your payment has been successfully submitted. We’ve sent you an
email with all of the details of your order.
</Text>
</View>
<Button title="Got it, thanks!" onPress={() => setIsOpen(false)} />
</ModalPanel>
</View>
</Modal>
</View>
);
}
const modalContainerStyle: ViewStyle = {
width: "100%",
height: "100%",
alignItems: "center",
justifyContent: "center",
padding: 40,
backgroundColor: "rgba(0, 0, 0, 0.5)",
};
const modalPanelStyle = {
padding: 20,
width: 300,
backgroundColor: "white",
};
const modalTitleStyle: TextStyle = { fontSize: 20, fontWeight: "700" };
const modalPanelContentStyle = { paddingTop: 20, paddingBottom: 20 };
Examples
Showing/hiding the modal
Modals are controlled components, meaning that you have to provide and manage the open state yourself using the open
prop and the onClose
callback.
The onClose
callback is called when an modal is dismissed, which happens when the user clicks outside the ModalPanel
. In this callback set the open
state back to false
to close the modal.
import { Modal, ModalPanel, ModalTitle } from 'headlessui-react-native'
import { useState } from 'react'
function Example() {
// The open/closed state lives outside of the `Modal` and is managed by you
let [isOpen, setIsOpen] = useState(true)
function async handleDeactivate() {
await fetch('/deactivate-account', { method: 'POST' })
setIsOpen(false)
}
return (
<Modal open={isOpen} onClose={() => setIsOpen(false)}>
<ModalPanel>
<ModalTitle>Deactivate account</ModalTitle>
<Text>This will permanently deactivate your account</Text>
<Text>Are you sure you want to deactivate your account? All of your data will be permanently removed.</Text>
{/*
You can render additional buttons to dismiss your
modal by setting `open` to `false`.
*/}
<Button title="Cancel" onPress={() => setIsOpen(false)}/>
<Button title="Deactivate" onPress={handleDeactivate}/>
</ModalPanel>
</Modal>
)
}
For situations where you don't have easy access to your open/close state, Headless UI provides a CloseButton
component that will close the nearest modal ancestor when clicked.
import { CloseButton } from "headlessui-react-native";
import { MyModal } from "./my-modal";
function Example() {
return (
<MyModal>
{/* ... */}
<CloseButton>
<Text>Cancel</Text>
</CloseButton>
</MyModal>
);
}
Scrollable modals
import { Modal, ModalPanel, ModalTitle } from "headlessui-react-native";
import React, { useState } from "react";
import { Button, Text, TextStyle, View, ViewStyle } from "react-native";
export function ScrollableModalExample() {
const [isOpen, setIsOpen] = useState(false);
return (
<View>
<Button title="Open dialog" onPress={() => setIsOpen(true)} />
<Modal onClose={() => setIsOpen(false)} open={isOpen}>
<View style={modalContainerStyle}>
<ModalPanel scrollable style={modalPanelStyle}>
<ModalTitle style={modalTitleStyle}>Payment successful</ModalTitle>
<View style={modalPanelContentStyle}>
<Text>
Your payment has been successfully submitted. We’ve sent you an
email with all of the details of your order.
</Text>
<Text>
Your payment has been successfully submitted. We’ve sent you an
email with all of the details of your order.
</Text>
<Text>
Your payment has been successfully submitted. We’ve sent you an
email with all of the details of your order.
</Text>
<Text>
Your payment has been successfully submitted. We’ve sent you an
email with all of the details of your order.
</Text>
<Text>
Your payment has been successfully submitted. We’ve sent you an
email with all of the details of your order.
</Text>
<Text>
Your payment has been successfully submitted. We’ve sent you an
email with all of the details of your order.
</Text>
</View>
<Button title="Got it, thanks!" onPress={() => setIsOpen(false)} />
</ModalPanel>
</View>
</Modal>
</View>
);
}
const modalContainerStyle: ViewStyle = {
width: "100%",
height: "100%",
alignItems: "center",
justifyContent: "center",
padding: 40,
backgroundColor: "rgba(0, 0, 0, 0.5)",
};
const modalPanelStyle = {
padding: 20,
width: 300,
backgroundColor: "white",
};
const modalTitleStyle: TextStyle = { fontSize: 20, fontWeight: "700" };
const modalPanelContentStyle = { paddingTop: 20, paddingBottom: 20 };
Component API
Modal
The main modal component. This has predefined roles, so it cannot be rendered as another component
using the as
prop.
Prop | Default | Description |
---|---|---|
open | false | Boolean Whether the modal is open or not. |
onClose | Called when the Modal is dismissed (via outside click of the ModalPanel ). Typically used to close the modal by setting open to false. |
Render Prop | Description |
---|---|
open | Boolean Whether the modal is open or not. |
ModalPanel
This indicates the panel of your actual Modal. Clicking outside of this component will trigger the onClose
of the Modal
component.
Prop | Default | Description |
---|---|---|
as | View | String The element the modal panel should render as. |
Render Prop | Description |
---|---|
open | Boolean Whether the modal is open or not. |
ModalTitle
This is the title for your Modal.
Prop | Default | Description |
---|---|---|
as | Text | String The element the modal title should render as. |
Render Prop | Description |
---|---|
open | Boolean Whether the modal is open or not. |
CloseButton
This button will close the nearest Modal
ancestor when clicked.
Prop | Default | Description |
---|---|---|
as | Pressable | String The element the close button should render as. |