Skip to main content

Modal

Appears from the bottom of the screen and fills up the entire screen, requiring user action to clear it.

github
View source code
import { Modal } from '@uhg-abyss/mobile';
() => {
const [isVisible, setIsVisible] = useState(false);
return (
<React.Fragment>
<Modal heading="Enter heading here" isVisible={isVisible}>
<Modal.Section>
<Button
onPress={() => setIsVisible(false)}
variant="destructive"
size="small"
>
Click to close modal
</Button>
</Modal.Section>
</Modal>
<Button
onPress={() => setIsVisible(true)}
>
Toggle Modal
</Button>
</React.Fragment>
);
};

useState

Pass the value from the useState hook to the isVisible modal prop to set the open state of the modal.

Heading

Use the heading prop to set the heading of the modal. This is optional but highly encouraged for accessibility.

If the heading is long, it will automatically be placed at the top of the scroll content area rather than the header bar, with a compact version appearing in the header as the user scrolls.

Note

Use the forceHeadingBelow prop to prevent the heading from appearing in the header bar until the user scrolls, regardless of heading length. This is useful when targeting various devices and/or your header layout needs to remain consistent.

Scrollable

Use the scrollable prop to make the content scrollable. Setting the prop to false changes the Modal's content container from a ScrollView to a View. Defaults to true.

Action Buttons

Action Buttons can be placed on either the left or right side of the header using the actionLeft and actionRight props. Use the onActionLeftPress prop to fire a callback when the left action is pressed, and onActionRightPress prop to fire a callback when the right action is pressed.

If one of the actions is an icon, make sure to use the heading and isScreenReadable props on the icon for accessibility.

Use the footer prop to place content at the bottom of the modal.

Wrap content in a Modal.Section component to add padding to the content.

onClose
iOS

Use onClose to close the modal when swiping the modal down on iOS devices.

() => {
const [modalVisible, setModalVisible] = useState(false);
return (
<Modal
heading="Swipeable Modal"
isVisible={modalVisible}
actionLeft={
<IconSymbol
icon="close"
color="$semantic.color.icon.interactive.rest.primary"
title="Close"
isScreenReadable
/>
}
onActionLeftPress={() => setModalVisible(false)}
onClose={() => setModalVisible(false)}
>
<Modal.Section>
<Text>Swipe the modal down</Text>
</Modal.Section>
</Modal>
);
};

Advanced Layout

Layouts like BottomSheet and Modal can be used in combination with each other to create flows.

NameTypeDefaultRequiredDescription
actionLeft
React.ReactNode | undefined
--
The action placed on the left side of the header
actionRight
React.ReactNode | undefined
--
The action placed on the right side of the header
children
React.ReactNode | undefined
--
Content inside of the modal
footer
React.ReactNode | undefined
--
Content inside the footer section of the modal
forceHeadingBelow
boolean | undefined
false
-
When true, the heading is always rendered below the header bar (in the
scrollable content area) rather than inside the header itself. The compact
heading still appears in the header once the user scrolls past it.
Use this when you want consistent visual hierarchy regardless of heading length.
heading
string | undefined
--
The heading of the modal
hideBorder
boolean | undefined
false
-
Flag to hide the header border
isVisible
boolean | undefined
false
-
Flag to check if modal is visible
onActionLeftPress
Abyss.GestureResponderEventHandler
--
Callback fired when the action left button is pressed
onActionRightPress
Abyss.GestureResponderEventHandler
--
Callback fired when the action right button is pressed
onClose
Abyss.NativeSyntheticEventHandler
--
Callback fired when the modal is triggered to close
onDismiss
() => void | undefined
--
Callback fired when the modal is closed
scrollable
boolean | undefined
true
-
Flag to make the modal scrollable. Setting to false will
turn the Modal's content container into a View
showsVerticalScrollIndicator
boolean | undefined
false
-
Flag to show the vertical scroll indicator
sticker
React.ReactNode | undefined
--
Content at the top of the modal that stays in the header
and does not scroll

Modal.Section Props

NameTypeDefaultRequiredDescription
children
React.ReactNode
-
Content rendered inside the section.

Class NameDescription
abyss-modal-rootModal root element
abyss-modal-headerModal header container
abyss-modal-action-left-buttonAction left container
abyss-modal-children-containerModal content
abyss-modal-action-right-buttonAction right container
abyss-modal-heading-containerModal heading container
abyss-modal-headingModal heading element
abyss-modal-long-headingModal heading element
abyss-modal-footerModal footer container

Modal.Section Classes

Class NameDescription
abyss-modal-section-rootModal section root element

Focus Guidance

Abyss does not control the focus of components on the screen when the Modal is toggled off. To meet accessibility guidelines, the focus must be set to the previous node when closed. The useSetFocus hook can be used for this.

For example, if a button is pressed to open a Modal, focus must return to that button once the Modal is closed, so that a screen reader or keyboard user may continue using the app where they left off.

Token NameValue
modal.color.surface.header
#FFFFFF
modal.color.surface.content
#FFFFFF
modal.color.border.header
#CBCCCD
modal.color.text.heading.sm
#323334
modal.color.text.heading.lg
#002677
modal.color.text.action.rest
#196ECF
modal.color.text.action.active
#004BA0
modal.color.icon.nav.rest
#002677
modal.color.icon.nav.active
#00184D
modal.color.icon.utility.rest
#4B4D4F
modal.color.icon.utility.active
#323334
modal.border-width.bottom.header
1
modal.sizing.all.icon.utility
24
modal.spacing.padding.all.content
16
modal.spacing.padding.horizontal.header
16
modal.spacing.padding.top.header
6
modal.spacing.padding.bottom.header
8
modal.spacing.gap.horizontal.header
18
modal.spacing.gap.vertical.header
24
Table of Contents