Edit page

Modal

Modal allows prompting users to take or complete an action.

Basic Usage

To implement the Modal component, you need to import it first:

import {
Modal,
ModalHeader,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalTitle,
} from '@react-ui-org/react-ui';

And use it:

See API for all available options.

General Guidelines

  • Use modals to confirm an action, display a blocking alert, or reveal contextual options or settings that cannot be displayed in line with the parent content.

  • The title should communicate the purpose of the modal rather than a generic text. Eg. “Delete the user?” tells more than “Are you sure?” or “Warning”.

  • Modal actions should correspond to the modal purpose, too. E.g. “Delete” tells better what happens rather than “OK”.

  • Modal automatically focuses the first form field by default which allows users to confirm the modal by hitting the enter key. When no field is found then the primary button (in the footer) is focused. To turn this feature off, set the autofocus prop to false.

  • Avoid stacking of modals. While it may technically work, the modal is just not designed for that.

Composition

Modal is decomposed into the following components:

Using different combinations, you can compose different kinds of modals, e.g. dialog modal, blocking modal, scrollable modal, etc.

ModalHeader

ModalHeader is an optional part of the Modal which allows you to display the title of the modal and its close button.

It is recommended to compose ModalHeader from the following elements. For title, use ModalTitle. For the close button, use ModalCloseButton, however it can be omitted if a close button is part of ModalFooter.

There are two ways how to position elements within the ModalHeader:

  1. You can use provided positioning. Place previously mentioned elements into the ModalHeader and use justify prop to set up the positioning of those elements.
  2. You can customize positioning using another component (e.g. Toolbar). In that case, set justify to stretch and position elements on your own.

ModalBody

ModalBody is a mandatory part of the Modal which allows you to display the content of the Modal.

Although the ModalBody allows you to display arbitrary content, you should not place content directly into the ModalBody, but wrap it with ModalContent first.

In case your content is expected to be long, consider wrapping ModalContent with ScrollView. Check Scrolling Long Content section below.

ModalFooter

ModalFooter is an optional part of the Modal which allows you to display user actions.

There are two ways to position buttons within the ModalFooter:

  1. You can use provided positioning. Place Button component (or any arbitrary element) and use justify prop to set up the positioning of those elements.
  2. You can customize positioning using another component (e.g. Toolbar). In that case, set justify to stretch and position elements on your own.

Sizes

Modal is available in three fixed-width sizes: small, medium, large and fullscreen. Modals of any size automatically shrink when they cannot fit the screen width.

On top of that, the modal can adjust to the width of its content.

👉 Please note the auto width may not function correctly in combination with other auto-layout mechanisms, e.g. the auto-width FormLayout. It's just too much magic that doesn't work together (yet?) 🎩.

👉 Beware of horizontal FormLayout inside small modals. While automatic overflow handling comes to the rescue in this kind of scenario, you will be better off with the combination of auto-sized modal and horizontal FormLayout with a fixed label width (i.e. any other than auto, see the previous note).

Position

Modal can be aligned either to the top or center of the screen.

Keyboard Control

Modal can be controlled either by mouse or keyboard. To enhance user experience, primary action can be fired by pressing Enter key and the modal can be closed by pressing the Escape key.

To enable it, you just need to pass a reference to the buttons using primaryButtonRef and closeButtonRef props on Modal. The advantage of passing a reference to the button is that if the button is disabled, the key press will not fire the event.

👉 We strongly recommend using this feature together with Autofocus for a better user experience.

Autofocus

Autofocus is implemented to enhance the user experience by automatically focussing an element within the modal.

How does it work? It tries to find input, textarea, and select elements inside of Modal and moves focus into the first found. If none is found and the primaryButtonRef prop on Modal is set, then the primary button is focused.

Autofocus is enabled by default, so if you want to control the focus of elements manually, set the autoFocus prop on Modal to false.

Scrolling Long Content

When modals become too long for the user's viewport or device, they scroll independent of the page itself. This can be done in three ways using the scrolling option of the ModalBody component:

  • auto (default) — ModalBody is responsible for scrolling,
  • custom — you must provide a custom component to handle scrolling, typically an instance of ScrollView wrapping ModalContent,
  • none — entire Modal is responsible for scrolling.

Long Content and Autofocus

👉 If you wrap ModalContent with ScrollView, you may want to turn autoFocus off to prevent the modal from scrolling to the end immediately after being opened.

API

Prop nameTypeDefaultRequiredDescription

ModalHeader

Prop nameTypeDefaultRequiredDescription
childrennodetrue

Content of the header (preferably ModalTitle and ModalCloseButton).

idstringundefinedfalse

ID of the root HTML element.

justify'start' │ 'center' │ 'end' │ 'space-between' │ 'stretch''space-between'false

Horizontal alignment (distribution) of individual buttons.

ModalTitle

Prop nameTypeDefaultRequiredDescription
childrennodetrue

Content of the header (preferably ModalTitle and ModalCloseButton).

idstringundefinedfalse

ID of the root HTML element.

levelnumber2false

Optional heading level. Preferably 1 or 2 should be used, see W3C recommendation.

ModalCloseButton

Prop nameTypeDefaultRequiredDescription
disabledboolfalsefalse

If true, close button will be disabled.

idstringundefinedfalse

ID of the root HTML element.

refFunction │ { "current": "any" }undefinedfalse

Reference forwarded to the button element.

ModalBody

Prop nameTypeDefaultRequiredDescription
childrennodenullfalse

Nested elements. Supported types are:

  • ModalContent
  • ScrollView (scrolling: 'custom' must be set)

You can also provide a custom component responsible for scrolling and displaying content correctly. At most one nested element is allowed. If none are provided nothing is rendered.

idstringundefinedfalse

ID of the root HTML element.

scrolling'auto' │ 'custom' │ 'none''auto'false

Scrolling mode:

  • auto: scrolling is enabled on ModalBody.
  • custom: use if providing a custom scrolling component, e.g. an instance of ScrollView.
  • none: scrolling is disabled on ModalBody and the entire Modal is scrollable instead.

ModalContent

Prop nameTypeDefaultRequiredDescription
childrennodenullfalse

Content of the modal.

idstringundefinedfalse

ID of the root HTML element.

ModalFooter

Prop nameTypeDefaultRequiredDescription
childrennodetrue

Content of the footer (preferably nested Button elements).

idstringundefinedfalse

ID of the root HTML element.

justify'start' │ 'center' │ 'end' │ 'space-between' │ 'stretch''center'false

Horizontal alignment (distribution) of individual buttons.

Theming

Custom PropertyDescription
--rui-Modal__padding-xInline padding of individual modal components
--rui-Modal__padding-yBlock padding of individual modal components
--rui-Modal__backgroundModal background (including url() or gradient)
--rui-Modal__box-shadowModal box shadow
--rui-Modal__separator__widthWidth of separator between modal header, body, and footer
--rui-Modal__separator__colorColor of separator between modal header, body, and footer
--rui-Modal__outer-spacing-xsSpacing around modal, xs screen size
--rui-Modal__outer-spacing-smSpacing around modal, sm screen size and bigger
--rui-Modal__header__gapModal header gap between children
--rui-Modal__footer__backgroundModal footer background (including url() or gradient)
--rui-Modal__footer__gapModal footer gap between children
--rui-Modal__backdrop__backgroundModal backdrop background (including url() or gradient)
--rui-Modal--auto__min-widthMin width of auto-sized modal (when enough screen estate)
--rui-Modal--auto__max-widthMax width of auto-sized modal (when enough screen estate)
--rui-Modal--small__widthWidth of small modal
--rui-Modal--medium__widthWidth of medium modal
--rui-Modal--large__widthWidth of large modal
--rui-Modal--fullscreen__widthWidth of fullscreen modal
--rui-Modal--fullscreen__heightHeight of fullscreen modal