Web component

<p-modal>

Modal dialog built on the native <dialog> element

Import
@parallelogram-js/core/components/PModal
Tag
p-modal

Playground

About

Opening calls showModal(), so the dialog renders in the top layer, the rest of the page is inert and focus stays inside it. The dialog is named after its title slot. Escape and the backdrop close it unless its settings say otherwise, focus returns to the element that had it before opening once no other modal is still open, and page scroll stays locked while any modal is open.

Open it with the open attribute, the open() method, or a [data-modal] trigger handled by the Modal component.

Accessibility

The dialog is modal, named by its title, and returns focus when it closes. Give every modal a title.

Without JavaScript

The title, content and actions are the page's own markup, so before the module loads they are ordinary elements sitting in the flow rather than a dialog. The package stylesheet hides the element while scripts are running, so that content does not appear inline for the moment before it upgrades; with scripting off it stays visible and readable, which is better than content nothing is coming to bring back.

Usage

Register the component and the framework loads it the first time a page contains p-modal.

import { Parallelogram } from '@parallelogram-js/core';

const app = Parallelogram.create();
app.components.add('p-modal', () => import('@parallelogram-js/core/components/PModal'));
app.run();

Attributes

NameTypeDefaultDescription
openflagnonePresent while the modal is open; add or remove it to open or close the modal
close-labelstringCloseThe accessible name of the close button For every instance, PModal.defaults.closeLabel.
data-modal-sizexs | sm | md | lg | xl | fullscreenmdThe panel width
data-modal-closablebooleantruefalse hides the close button and ignores Escape and the backdrop; data-modal-close buttons still close the modal
data-modal-backdrop-closebooleantrueClose when the backdrop is clicked
data-modal-keyboardbooleantrueClose with Escape
data-modal-stateset by the componentclosed | opening | open | closingnoneThe modal's state

Methods

NameSignatureDescription
open(options?: { returnFocus?: HTMLElement | null }) => voidOpen the modal; returnFocus is the element to focus when it closes, or null to leave focus alone
close() => voidClose the modal once its closing animation has finished
toggle(force?: boolean) => voidOpen or close the modal

Events

NameDetailDescription
p-modal:open{ modal: HTMLElement }The modal opened; bubbles out of shadow roots DOM event
p-modal:close{ modal: HTMLElement }The modal has closed; bubbles out of shadow roots DOM event

Slots

NameDescription
titleThe title, which also names the dialog
defaultThe content
secondaryA secondary action, such as deleting what the modal is about, held against the leading end of the footer and away from the buttons in actions; the footer shows while either slot has something in it
actionsFooter buttons; any element with data-modal-close closes the modal

Shadow parts

NameDescription
panelThe <dialog>; style the page behind with ::part(panel)::backdrop
headerThe title row
titleThe title container
closeThe close button
contentThe scrolling content area
footerThe actions row

CSS custom properties

NameDefaultDescription
--modal-panel-bordervar(--surface-dialog-border-color)Panel border colour; follows the dialog surface
--modal-border-widthvar(--surface-dialog-border-width)Panel border width; follows the dialog surface
--modal-shadow-colorvar(--color-shadow)Colour the panel shadow is built from
--modal-header-bgvar(--surface-dialog-color-bg)Header background; follows the dialog surface
--modal-header-paddingvar(--panel-header-padding)Header padding; follows the panel family
--modal-footer-bgvar(--surface-dialog-color-bg)Footer background; follows the dialog surface
--modal-footer-paddingvar(--panel-footer-padding)Footer padding; follows the panel family
--modal-content-paddingvar(--panel-padding)Padding around the content; follows the panel family, and sets the close button inset
--modal-gap0.5emSpace between the title and the close button
--modal-close-size1.75emSize of the close button, which sets the least header height
--modal-close-hover-bgvar(--color-hover)Close button background on hover
--modal-btn-bgvar(--button-secondary-bg)Slotted button background; follows the secondary button
--modal-btn-colorvar(--button-secondary-color)Slotted button text; follows the secondary button
--modal-btn-bordervar(--button-secondary-border)Slotted button border; follows the secondary button
--modal-btn-hover-bgvar(--button-secondary-hover-bg)Slotted button background on hover
--modal-btn-hover-bordervar(--button-secondary-hover-border)Slotted button border on hover
--modal-btn-min-height3.125emLeast height of a slotted button
--modal-btn-primary-bgvar(--button-primary-bg)A .primary slotted button background; set the button token to change every component, or this one for modals alone
--modal-btn-primary-colorvar(--button-primary-color)A .primary slotted button text colour
--modal-btn-primary-hover-bgvar(--button-primary-hover-bg)A .primary slotted button background on hover
--modal-btn-danger-bgvar(--button-danger-bg)A .danger slotted button background
--modal-btn-danger-colorvar(--button-danger-color)A .danger slotted button text colour
--modal-btn-danger-hover-bgvar(--button-danger-hover-bg)A .danger slotted button background on hover
--modal-max-width92vwMost width the panel takes, whatever size it is given
--modal-fullscreen-inset3emSpace left around a fullscreen modal
--modal-transition0.2s easeLength and easing of hover and focus changes inside the panel
--modal-disabled-opacitynoneOpacity of a disabled control in the panel
--modal-size-xs18.75emWidth of size='xs'
--modal-size-md40emWidth of size='md'
--modal-size-lg50emWidth of size='lg'
--modal-size-xl62.5emWidth of size='xl'
--modal-animation-duration0.2sLength of the opening and closing animations
--modal-animation-easingnoneEasing of the animations
--modal-backdrop-bgcolor-mix(in srgb, var(--color-surface) 95%, transparent)Colour of the page behind the modal; the page surface at 95%, so white in light mode and the dark surface in dark mode
--modal-panel-bgvar(--surface-dialog-color-bg)Panel background
--modal-panel-colorvar(--surface-dialog-color-text)Panel text colour
--modal-radiusnonePanel corner radius
--modal-shadowvar(--surface-dialog-shadow)Panel shadow
--modal-close-insetvar(--modal-padding-y)Distance from the top of the panel to the close button, and the least height of the header, so the title sits on the button's line
--modal-content-gapvar(--modal-space-xl)Space between the elements the page puts in the modal, which give up the margins the browser would give them so the content meets the panel's padding
--modal-close-inset-xvar(--modal-content-padding)Distance from the side of the panel to the close button, following the content's own padding so the button lines up with what sits under it; set it where a page gives the panel padding more than one value
--modal-padding-xnoneHorizontal padding
--modal-padding-ynoneVertical padding
--modal-max-heightnoneTallest the panel gets before its content scrolls
--modal-size-smnoneWidth of the sm size; xs, md, lg and xl match