Modal

Dialog overlay triggered by a button, for focused content or actions.

---
import Heading from "@core-elements/heading/Heading.astro";
import Text from "@core-elements/text/Text.astro";
import Form from "@forms/form/Form.astro";
import Input from "@forms/input/Input.astro";
import Submit from "@forms/submit/Submit.astro";
import Textarea from "@forms/textarea/Textarea.astro";
import Modal from "@wrappers/modal/Modal.astro";
import Split from "@wrappers/split/Split.astro";
import CustomSection from "@builders/custom-section/CustomSection.astro";
---

<Modal
contentSections={
  [
    {
      "_component": "page-sections/builders/custom-section",
      "label": "",
      "paddingHorizontal": "lg",
      "paddingVertical": "lg",
      "backgroundColor": "surface",
      "contentSections": [
        {
          "_component": "building-blocks/wrappers/split",
          "distributionMode": "half",
          "alignmentVertical": "center",
          "reverse": false,
          "label": "",
          "minSplitWidth": 200,
          "firstColumnContentSections": [
            {
              "_component": "building-blocks/core-elements/heading",
              "text": "Let's get started",
              "level": "h2",
              "size": "md"
            },
            {
              "_component": "building-blocks/core-elements/text",
              "text": "This modal skips the optional header and instead uses a split layout with supporting copy beside a simple contact form."
            }
          ],
          "secondColumnContentSections": [
            {
              "_component": "building-blocks/forms/form",
              "action": "./",
              "formBlocks": [
                {
                  "_component": "building-blocks/forms/input",
                  "label": "Name",
                  "name": "name",
                  "type": "text",
                  "placeholder": "Your name",
                  "required": true
                },
                {
                  "_component": "building-blocks/forms/input",
                  "label": "Email",
                  "name": "email",
                  "type": "email",
                  "placeholder": "you@example.com",
                  "required": true
                },
                {
                  "_component": "building-blocks/forms/textarea",
                  "label": "Message",
                  "name": "message",
                  "placeholder": "Tell us what you need",
                  "required": true
                },
                {
                  "_component": "building-blocks/forms/submit",
                  "text": "Send message",
                  "variant": "primary"
                }
              ]
            }
          ]
        }
      ]
    }
  ]
} label="Modal" size="md" triggerSize="md" triggerText="Open modal" triggerVariant="secondary"
/>
---
blocks:
  _component: building-blocks/wrappers/modal
  label: Modal
  triggerText: Open modal
  triggerVariant: secondary
  triggerSize: md
  size: md
  contentSections:
    - _component: page-sections/builders/custom-section
      label: ''
      paddingHorizontal: lg
      paddingVertical: lg
      backgroundColor: surface
      contentSections:
        - _component: building-blocks/wrappers/split
          distributionMode: half
          alignmentVertical: center
          reverse: false
          label: ''
          minSplitWidth: 200
          firstColumnContentSections:
            - _component: building-blocks/core-elements/heading
              text: Let's get started
              level: h2
              size: md
            - _component: building-blocks/core-elements/text
              text: This modal skips the optional header and instead uses a split layout with supporting copy beside a simple contact form.
          secondColumnContentSections:
            - _component: building-blocks/forms/form
              action: ./
              formBlocks:
                - _component: building-blocks/forms/input
                  label: Name
                  name: name
                  type: text
                  placeholder: Your name
                  required: true
                - _component: building-blocks/forms/input
                  label: Email
                  name: email
                  type: email
                  placeholder: you@example.com
                  required: true
                - _component: building-blocks/forms/textarea
                  label: Message
                  name: message
                  placeholder: Tell us what you need
                  required: true
                - _component: building-blocks/forms/submit
                  text: Send message
                  variant: primary
---

Overview #

A dialog overlay triggered by a button. Uses the native Popover API for built-in focus trapping, Escape to close, and backdrop. Content is rendered inside the modal body using content sections. Any Button or Card on the page can also open a modal by setting its link to ^modal-{label}, where {label} is the slugified modal label (e.g. ^modal-my-modal).

Properties #

label string

Accessible label for the modal dialog.

heading string

Optional heading displayed at the top of the modal.

triggerText string | default: Open

Text displayed on the button that opens the modal.

triggerVariant enum | default: primary

Visual style of the trigger button.

Accepted values:
  • primary
  • secondary
  • tertiary
  • ghost
  • text

triggerSize enum | default: md

Size of the trigger button.

Accepted values:
  • sm
  • md
  • lg

triggerIconName enum

Optional icon for the trigger button. Sourced from [Heroicons](https://heroicons.com/).

size enum | default: md

Maximum width of the modal dialog.

Accepted values:
  • sm
  • md
  • lg
  • xl

contentSections array | default: array

Content blocks displayed inside the modal.

Examples #

With header #

---
import Button from "@core-elements/button/Button.astro";
import List from "@core-elements/list/List.astro";
import ListItem from "@core-elements/list/ListItem.astro";
import Text from "@core-elements/text/Text.astro";
import ButtonGroup from "@wrappers/button-group/ButtonGroup.astro";
import Modal from "@wrappers/modal/Modal.astro";
import CustomSection from "@builders/custom-section/CustomSection.astro";
---

<Modal
contentSections={
  [
    {
      "_component": "page-sections/builders/custom-section",
      "label": "",
      "maxContentWidth": "md",
      "paddingHorizontal": "lg",
      "paddingVertical": "lg",
      "contentSections": [
        {
          "_component": "building-blocks/core-elements/text",
          "text": "Use this modal pattern to highlight key details, guide someone toward a next action, or present supporting information without leaving the current page."
        },
        {
          "_component": "building-blocks/core-elements/list",
          "items": [
            {
              "text": "Summarize the main value or context in a compact space.",
              "iconName": "check"
            },
            {
              "text": "Reinforce the message with a short checklist or supporting points.",
              "iconName": "check"
            },
            {
              "text": "Offer clear follow-up actions that fit the page context.",
              "iconName": "check"
            }
          ],
          "direction": "vertical",
          "alignmentHorizontal": "start",
          "size": "md",
          "listType": "icon"
        },
        {
          "_component": "building-blocks/wrappers/button-group",
          "direction": "row",
          "alignmentHorizontal": "start",
          "buttonSections": [
            {
              "_component": "building-blocks/core-elements/button",
              "text": "View details",
              "variant": "primary"
            },
            {
              "_component": "building-blocks/core-elements/button",
              "text": "Dismiss",
              "variant": "secondary"
            }
          ],
          "label": ""
        }
      ]
    }
  ]
} heading="Explore next steps" label="Learn more modal" size="md" triggerSize="md" triggerText="Open modal" triggerVariant="primary"
/>
---
blocks:
  _component: building-blocks/wrappers/modal
  label: Learn more modal
  heading: Explore next steps
  triggerVariant: primary
  triggerText: Open modal
  triggerSize: md
  size: md
  contentSections:
    - _component: page-sections/builders/custom-section
      label: ''
      maxContentWidth: md
      paddingHorizontal: lg
      paddingVertical: lg
      contentSections:
        - _component: building-blocks/core-elements/text
          text: Use this modal pattern to highlight key details, guide someone toward a next action, or present supporting information without leaving the current page.
        - _component: building-blocks/core-elements/list
          items:
            - text: Summarize the main value or context in a compact space.
              iconName: check
            - text: Reinforce the message with a short checklist or supporting points.
              iconName: check
            - text: Offer clear follow-up actions that fit the page context.
              iconName: check
          direction: vertical
          alignmentHorizontal: start
          size: md
          listType: icon
        - _component: building-blocks/wrappers/button-group
          direction: row
          alignmentHorizontal: start
          buttonSections:
            - _component: building-blocks/core-elements/button
              text: View details
              variant: primary
            - _component: building-blocks/core-elements/button
              text: Dismiss
              variant: secondary
          label: ''
---