Modal 10.17.4
A modal is an interface element that appears over other content. It requires an interaction from the user before they can return to whatever is underneath.
Based on Headless UI.
Anatomy
<Modal> <Modal.Backdrop /> <Modal.Title>...<Modal.Title> <Modal.Panel>...<Modal.Panel> </Modal>
Default
<Modal />
can be opened by either a <Button />
or any other component with an onClick event. To manage the Modal's visibility, utilize the open
and onClose
properties.
"use client";
import React, { useState } from "react";
import { Modal, Button } from "@heathmont/moon-core-tw";
const Default = () => {
const [isOpen, setIsOpen] = useState(false);
const closeModal = () => setIsOpen(false);
const openModal = () => setIsOpen(true);
return (
<>
<Button onClick={openModal}>Open modal</Button>
<Modal open={isOpen} onClose={closeModal} className="z-50">
<Modal.Backdrop />
<Modal.Panel>
<div className="p-4 border-b-2 border-beerus">
<h3 className="text-moon-18 text-bulma font-medium">
Payment successful
</h3>
</div>
<div className="p-4">
<p className="text-moon-sm text-trunks">
{/* cSpell:disable */}
Your payment has been successfully submitted. We’ve sent you an
email with all of the details of your order. Lorem ipsum dolor sit
amet, consectetur adipiscing elit. Aliquam blandit massa at lorem
fermentum volutpat. Aliquam varius faucibus turpis, in facilisis
dui dictum ac. Nulla ac consequat enim. Ut lobortis ultricies
mauris eget volutpat. Aliquam aliquam nisl in nulla sagittis, eget
viverra est ullamcorper.
{/* cSpell:enable */}
</p>
</div>
<div className="p-4 border-t-2 border-beerus">
<Button onClick={closeModal}>Got it, thanks!</Button>
</div>
</Modal.Panel>
</Modal>
</>
);
};
export default Default;
Example with big content
<Modal />
component is versatile and can showcase content of any size.
"use client";
import { useState } from "react";
import { Modal, Button, IconButton } from "@heathmont/moon-core-tw";
import { ControlsCloseSmall } from "@heathmont/moon-icons-tw";
const WithBigContent = () => {
const [isOpen, setIsOpen] = useState(false);
const closeModal = () => setIsOpen(false);
const openModal = () => setIsOpen(true);
return (
<>
<Button onClick={openModal}>Open modal</Button>
<Modal open={isOpen} onClose={closeModal} className="z-50">
<Modal.Backdrop />
<Modal.Panel>
<div className="p-4 border-b-2 border-beerus">
<h3 className="text-moon-18 text-bulma font-medium">
Payment successful
</h3>
</div>
<div className="p-4">
<p className="text-moon-sm text-trunks">
{/* cSpell:disable */}
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam
blandit massa at lorem fermentum volutpat. Aliquam varius faucibus
turpis, in facilisis dui dictum ac. Nulla ac consequat enim. Ut
lobortis ultricies mauris eget volutpat. Aliquam aliquam nisl in
nulla sagittis, eget viverra est ullamcorper. Morbi vel eros sed
mauris dignissim congue et nec ligula. Duis quis tellus a est
facilisis finibus. Duis varius libero id arcu pretium, et ultrices
diam tincidunt. Aenean laoreet, velit at tempus eleifend, lectus
turpis interdum ipsum, ac porta elit libero at arcu. Nam maximus
magna vel orci pulvinar, et dignissim mi egestas. Pellentesque
dapibus rhoncus ex, a finibus tortor sagittis quis. In nunc
mauris, scelerisque vitae elit pulvinar, consequat accumsan leo.
Proin varius maximus erat sed convallis. Aliquam convallis turpis
turpis, eget euismod justo elementum at. Curabitur ligula velit,
volutpat eget lacus sed, congue hendrerit turpis. Ut justo felis,
ultricies et ornare quis, finibus ac lectus. Nam scelerisque felis
nec massa convallis, eu ornare mauris posuere. Vivamus lacinia
feugiat odio. Mauris cursus eu libero sit amet sollicitudin. Proin
urna lectus, sodales nec ultricies ut, pharetra a mauris. Cras
quis pharetra velit. Pellentesque magna erat, bibendum volutpat
facilisis vitae, euismod in odio. Donec id sem vehicula, mollis
eros porttitor, mattis sem. Etiam augue ligula, consectetur
lobortis ullamcorper a, ullamcorper a lectus. Nullam non auctor
quam. Morbi a lorem ut eros lobortis ultricies vitae sed lacus.
Proin auctor vestibulum lorem a porttitor. Nunc ullamcorper leo
risus. Integer tincidunt erat leo, ut lacinia est volutpat sit
amet. Nulla laoreet molestie pharetra. Suspendisse sed magna erat.
Fusce et orci orci. Suspendisse sit amet finibus mi. Integer
fringilla venenatis dolor, porttitor bibendum lorem mattis et.
Maecenas nisl nisl, finibus sed dolor vel, rhoncus euismod lorem.
Maecenas sit amet gravida nunc. Praesent iaculis nunc elit, ut
viverra nisl aliquam non. Donec eget ex velit. Pellentesque sed
laoreet nunc. Morbi eget augue cursus, laoreet lorem in, tempus
magna. Aliquam quis auctor nibh, id ornare sapien. Aenean sem
magna, tempus a tempus in, lobortis vitae nisi. Mauris lobortis
tellus sit amet elit maximus ornare. Sed interdum ac purus quis
feugiat. Praesent nunc quam, gravida placerat dui eget, tempus
pharetra urna. Maecenas eros augue, rutrum vitae maximus dictum,
consectetur ut orci. Phasellus ut consequat urna. Morbi
pellentesque sapien mauris, quis ornare diam ultricies eu.
Interdum et malesuada fames ac ante ipsum primis in faucibus.
Etiam tincidunt lacus purus, sit amet ultricies elit dapibus et.
Vestibulum at velit eu mauris tincidunt lobortis quis sed leo.
Vivamus non rhoncus massa, et bibendum ligula. Sed pulvinar,
tortor eu faucibus vestibulum, nunc magna laoreet leo, ut
elementum diam ipsum vitae purus. Vestibulum egestas sit amet elit
egestas auctor. Mauris vestibulum ex at erat viverra ultricies.
Suspendisse et nisi enim. Aenean ut velit sit amet diam aliquet
molestie non quis urna. Praesent nec arcu non nisl maximus tempus
in in ligula. Sed sodales eu elit facilisis tempus. Suspendisse
viverra porta velit, mollis tempor purus aliquam id. Vestibulum
sit amet vehicula dolor. Vestibulum orci nulla, sodales vitae
euismod at, aliquam egestas sapien. Pellentesque et massa et
lectus imperdiet ullamcorper. Integer sit amet semper nisl, sed
suscipit eros. Nunc quis quam leo. Pellentesque porttitor, ex
vitae ultrices interdum, sapien tellus dictum lectus, quis
convallis elit felis vitae nulla. Nulla volutpat cursus urna, sed
facilisis nisi consectetur sed. Praesent ac euismod odio. Mauris
laoreet id ante vel finibus. Nulla nec egestas mi. Aenean leo
lacus, imperdiet at lobortis nec, egestas ac mi. Praesent ut
molestie est. Sed est dui, rhoncus eget semper id, egestas in
sapien. Vestibulum aliquet, orci eget ultricies placerat, felis
leo euismod enim, efficitur lacinia nulla ipsum non odio. Etiam id
urna ut tortor egestas mattis. Nullam eget urna ac massa facilisis
auctor nec at diam. Aliquam imperdiet, tortor non dignissim
semper, eros sem congue lacus, a vehicula diam tellus ut ligula.
Sed eget porta nibh, nec interdum urna. In tempor placerat massa,
at imperdiet leo tincidunt eget. Vestibulum eu laoreet nisl, et
gravida mauris. Aliquam erat volutpat. Vivamus elit diam,
fringilla varius congue quis, dignissim non sapien. Curabitur a
magna vitae risus tempus vulputate. Ut metus metus, iaculis in
tincidunt ullamcorper, eleifend vitae mauris. Aliquam erat
volutpat. Nunc eu nisi placerat, feugiat eros non, fringilla
purus. Aliquam erat volutpat. Morbi sit amet imperdiet felis, sit
amet dapibus lacus. Sed aliquam ipsum vitae ipsum maximus
convallis. Donec quis nulla placerat, scelerisque tellus ut,
ullamcorper sapien. Pellentesque enim lacus, ornare mollis nisl
vitae, rutrum tincidunt mauris. Sed suscipit, augue in venenatis
ultrices, augue nunc viverra turpis, eget ornare tellus lectus sit
amet felis. In aliquam ullamcorper nulla sit amet tristique.
Pellentesque odio ipsum, pulvinar sit amet est eget, maximus
accumsan leo. Aenean consequat tellus vel pulvinar bibendum.
Suspendisse finibus volutpat nisl, id dictum est feugiat sit amet.
Pellentesque euismod lectus leo. Integer imperdiet nisi egestas
quam posuere, mollis imperdiet odio tincidunt. Nam non quam leo.
Vivamus vulputate metus sed velit laoreet euismod id et turpis.
Vestibulum dictum ac turpis quis ultrices. Vivamus non semper
nunc. Nullam vitae dignissim augue. Aliquam mollis nibh enim, sit
amet accumsan est suscipit ac. Cras dignissim aliquet turpis id
aliquet. Mauris erat magna, mattis ut ligula eu, ultricies
interdum dolor. Cras nec congue mi, vitae faucibus nisi. Fusce
tincidunt ultrices eleifend. Vestibulum sit amet porta lectus.
Fusce dapibus tortor in lectus vehicula lobortis. Vestibulum ac
felis congue, consectetur nunc sed, porttitor lorem. Maecenas non
ultrices diam, non molestie neque. Donec metus odio, bibendum nec
facilisis vel, mattis ut ex. Morbi luctus ex eu est tincidunt
lacinia. Sed commodo eget neque eget aliquet. Phasellus tincidunt
justo imperdiet nunc scelerisque, sit amet interdum lorem
dignissim. Lorem ipsum dolor sit amet, consectetur adipiscing
elit. Class aptent taciti sociosqu ad litora torquent per conubia
nostra, per inceptos himenaeos.
{/* cSpell:enable */}
</p>
</div>
<div className="p-4 border-t-2 border-beerus">
<Button onClick={closeModal}>Got it, thanks!</Button>
</div>
</Modal.Panel>
</Modal>
</>
);
};
export default WithBigContent;
Example with styled content
Enhance <Modal.Panel />
and <Modal.Backdrop />
sub-components by utilizing the className
property for customization.
"use client";
import { useState } from "react";
import { Modal, Button, IconButton } from "@heathmont/moon-core-tw";
import { ControlsCloseSmall } from "@heathmont/moon-icons-tw";
const WithStyledContent = () => {
const [isOpen, setIsOpen] = useState(false);
const closeModal = () => setIsOpen(false);
const openModal = () => setIsOpen(true);
return (
<>
<Button onClick={openModal}>Open modal</Button>
<Modal open={isOpen} onClose={closeModal} className="z-50">
<Modal.Backdrop />
<Modal.Panel className="lg:max-w-md bg-roshi text-goten rounded-none">
<IconButton
variant="ghost"
size="sm"
className="absolute top-4 end-5 text-goten"
onClick={closeModal}
>
<ControlsCloseSmall className="text-moon-24" />
</IconButton>
<div className="p-4 pt-11">
<div className="mt-2">
<h3 className="text-moon-24 text-goten font-medium text-center">
Your payment has been successfully submitted.
</h3>
</div>
</div>
<div className="p-4 flex items-center justify-center">
<Button variant="outline" onClick={closeModal}>
Got it, thanks!
</Button>
</div>
</Modal.Panel>
</Modal>
</>
);
};
export default WithStyledContent;
Example with Select
Boost the interactivity of your <Modal />
by adding components like <Dropdown />
, and more.
"use client";
import { useState } from "react";
import {
Modal,
Button,
Dropdown,
MenuItem,
IconButton,
} from "@heathmont/moon-core-tw";
import { ControlsCloseSmall } from "@heathmont/moon-icons-tw";
type Options = {
value: string;
label: string;
};
const sizes = [
{ value: "Small", label: "Small" },
{ value: "Medium", label: "Medium" },
{ value: "Large", label: "Large" },
];
const colors = [
{ value: "Red", label: "Red" },
{ value: "Blue", label: "Blue" },
{ value: "Green", label: "Green" },
];
const materials = [
{ value: "Leather", label: "Leather" },
{ value: "Silk", label: "Silk" },
{ value: "Cotton", label: "Cotton" },
{ value: "Wool", label: "Wool" },
];
const WithSelect = () => {
const [isOpen, setIsOpen] = useState(false);
const [size, setSize] = useState<Options | null>(null);
const [color, setColor] = useState<Options | null>(null);
const [material, setMaterial] = useState<Options | null>(null);
const closeModal = () => setIsOpen(false);
const openModal = () => setIsOpen(true);
return (
<>
<Button onClick={openModal}>Open modal</Button>
<Modal open={isOpen} onClose={closeModal} className="z-50">
<Modal.Backdrop />
<Modal.Panel>
<div className="border-b-[0.063rem] border-beerus pt-5 pb-4 px-6 relative">
<h3 className="text-moon-18 text-bulma font-medium">Modal title</h3>
<IconButton
variant="ghost"
size="sm"
className="absolute top-4 end-5"
onClick={closeModal}
>
<ControlsCloseSmall className="text-moon-24" />
</IconButton>
</div>
<div className="px-6 py-4 flex flex-col gap-3">
<Dropdown value={size} onChange={setSize} size="xl">
{({ open }) => (
<>
<Dropdown.Select
open={open}
label="xLarge"
placeholder="Choose size..."
data-test="data-test"
>
{size?.label}
</Dropdown.Select>
<Dropdown.Options>
{sizes.map((size, index) => (
<Dropdown.Option value={size} key={index}>
{({ selected, active }) => (
<MenuItem isActive={active} isSelected={selected}>
{size.label}
</MenuItem>
)}
</Dropdown.Option>
))}
</Dropdown.Options>
</>
)}
</Dropdown>
<Dropdown value={color} onChange={setColor} size="xl">
{({ open }) => (
<>
<Dropdown.Select
open={open}
label="xLarge"
placeholder="Choose color..."
data-test="data-test"
>
{color?.value}
</Dropdown.Select>
<Dropdown.Options>
{colors.map((color, index) => (
<Dropdown.Option value={color} key={index}>
{({ selected, active }) => (
<MenuItem isActive={active} isSelected={selected}>
{color.value}
</MenuItem>
)}
</Dropdown.Option>
))}
</Dropdown.Options>
</>
)}
</Dropdown>
<Dropdown value={material} onChange={setMaterial} size="xl">
{({ open }) => (
<>
<Dropdown.Select
open={open}
label="xLarge"
placeholder="Choose material..."
data-test="data-test"
>
{material?.value}
</Dropdown.Select>
<Dropdown.Options>
{materials.map((material, index) => (
<Dropdown.Option value={material} key={index}>
{({ selected, active }) => (
<MenuItem isActive={active} isSelected={selected}>
{material.value}
</MenuItem>
)}
</Dropdown.Option>
))}
</Dropdown.Options>
</>
)}
</Dropdown>
</div>
<div className="flex gap-2 p-4 justify-end pt-2">
<Button variant="outline" onClick={closeModal}>
Cancel
</Button>
<Button onClick={closeModal}>Create</Button>
</div>
</Modal.Panel>
</Modal>
</>
);
};
export default WithSelect;
Modal
These are props specific to the Modal component:
Name | Type | Default |
---|---|---|
open* | boolean | - |
onClose* | "() => void" | - |
Properties indicated with * are required.
Modal.Panel
These are props specific to the Modal.Panel component:
Name | Type | Default |
---|---|---|
className | string | - |
Modal.Backdrop
These are props specific to the Modal.Backdrop component:
Name | Type | Default |
---|---|---|
className | string | - |