Modal 10.16.0

ARIA
RTL

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;
        

          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-