Skip to content

Modal

A dialog that focuses the user's attention exclusively on an information via a window that is overlaid on primary content.

Based on the Chakra UI Dialog component. It is a multipart component and can be constructed in a number of ways as suggested by the docs below.

The <Modal>-component is the outmost component of all, it does not render any DOM-node, but provides context to all modal subcomponents within. It should always contain a <ModalBody>, and a button that closes it.

A minimum required working example could be:

import {
Button,
Modal,
ModalBody,
ModalCloseButton,
ModalHeader,
useDisclosure,
} from "@caspeco/casper-ui-library";
export default function Demo() {
const { isOpen, onOpen, onClose } = useDisclosure();
return (
<>
<Button onClick={onOpen}>Open Modal</Button>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalHeader>
Modal title
<ModalCloseButton />
</ModalHeader>
<ModalBody>Lorem ipsum dolor sit amet consectetur adipisicing elit. Tenetur magnam.</ModalBody>
</Modal>
</>
);
}

Both props isOpen and onClose are required to pass to the Modal-component. There is no need to write and handle a custom state for the open/close-state of the modal, instead use the useDisclosure-hook as in the example above. See it’s docs for any questions on usage.

A common Modal structure contains both a header and a footer, and most likely some styling should be applied, such as padding. The modal footer should in most cases contain a primary and secondary action, of which the latter will call the onClose-action.

import {
Button,
Modal,
ModalBody,
ModalCloseButton,
ModalFooter,
ModalHeader,
Stack,
Text,
ThemeFontSize,
ThemeFont,
ThemeSpace,
useDisclosure,
} from "@caspeco/casper-ui-library";
export default function Demo() {
const { isOpen, onOpen, onClose } = useDisclosure();
const onSave = () => {}; // Perform some save action
return (
<>
<Button onClick={onOpen}>Open Modal</Button>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalHeader display="flex" alignItems="center" justifyContent="space-between" p={ThemeSpace.Medium}>
<Text fontFamily={ThemeFont.SubHeader} fontWeight="medium" fontSize={ThemeFontSize.XLarge}>
Title
</Text>
<ModalCloseButton />
</ModalHeader>
<ModalBody px={ThemeSpace.Medium} pb={ThemeSpace.Medium}>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Tenetur magnam.
</ModalBody>
<ModalFooter display="flex" justifyContent="flex-end" px={ThemeSpace.Medium} pb={ThemeSpace.Medium}>
<Stack direction="row" spacing={ThemeSpace.Medium}>
<Button variant="ghost" onClick={onClose}>
Cancel
</Button>
<Button variant="primary" onClick={onSave}>
Save
</Button>
</Stack>
</ModalFooter>
</Modal>
</>
);
}
  • <Modal> provides context, size, theming, and accessibility properties to all other modal components. It doesn’t render any DOM node.

  • <ModalHeader> Optional header that labels the modal dialog.

    • To make the modal header stick to the top, use the sticky prop: <ModalHeader sticky={true}>
  • <ModalCloseButton> A button that closes the modal.

    • You don’t need to pass any close action to the ModalCloseButton, it recieves and calls the onClose action from the Modal-context on its own

    • Use isAbsolutePositioned={true} to make the button stay fixed to the top right corner and “float” above other modal content

  • <ModalBody> The wrapper that contains the modal’s main content. It has very little styling of it’s own, you’re meant to add content to it, and style that content.

  • <ModalFooter> The footer that should contain modal actions. Will be displayed with a box shadow when the Modal Body element has overflowing content, indicating that something is accessible behind the footer through scrolling the modal content.

The size property of the modal is applied as growing max widths of the modal on larger screens (min-width: 30em).

On smaller screens, the modal will always fill up the full width of the screen and appear as a “bottom sheet”. This is by design and cannot be overriden, with the only exception of size="full" which covers the entire viewport on any screen size.

By default, when content of the modal body overflows it’s container, the scrolling happens within the modal.

Using scrollBehavior="outside" scrolling will happen outside of the modal instead.