Skip to content

Modal โ€‹

A centered overlay dialog with header / title / body / footer slots, six content sizes, six theme colours, and a modelValue binding contract that matches drawer / popover / toast. Renders into a body portal to escape transformed ancestors and stays fully invisible while closed (no shadow halo bleed). Toggle Vue / CSS to switch the live demo and source together.

Basic โ€‹

Simple modal with title, body, and close button.

Vue SFC

The modal projects four regions:

SlotAliasRenders
headerheadReplaces the whole default header (title + โœ•)
titleโ€”Just the heading, keeping the default โœ•
body(default slot)Main content โ€” unslotted children land here
footerfootAction row under the body

header and footer are the preferred names and match mono-drawer. The original head and foot still work, so existing markup keeps rendering. If you supply both spellings for the same region, the alias wins (header beats head) and the other is ignored.

Vue SFC

Sizes โ€‹

size sets the content scale โ€” header/title type, body type, padding, the close button and the corner radius โ€” across xs, sm, md (default), lg, xl and xxl. It does not change the panel width: every panel in the demo below is the same width. Use width for that, so a compact sm dialog can still be wide.

Changed

size used to be a width preset (sm 380px โ€ฆ xl 880px) and did nothing to the type scale. Panels that relied on size for their measure should now pass width instead.

Vue SFC

Width & height โ€‹

For full control, set width, height, min-width, max-width, min-height or max-height directly. Each accepts a CSS string ("760px", "12rem", "80%") or a number โ€” numbers are treated as px (so :width="480" โ†’ 480px). Both kebab-case (min-width) and camelCase (minWidth) work. Set both width and height to "100%" for true full screen.

Vue SFC

Auto full-screen โ€‹

Set auto-fullscreen and the modal fills the screen on small viewports. It defaults to sm (under 640px); pass md, lg, xl or 2xl to move the boundary. Any authored width / height is overridden while it applies and restored above it.

Scroll lock โ€‹

While open, a modal locks page scroll โ€” lock-scroll, default true. Opt out with :lock-scroll="false" when the page behind should stay scrollable.

vue
<mono-modal v-model="open" :lock-scroll="false" />

The lock is shared, not per-instance: overlapping overlays (a modal opened from a drawer, stacked modals, a sidebar) all draw on one lock, so scroll is released only when the last one that wanted it closes. mono-sidebar takes the same prop.

Stacked โ€‹

Set stackable to let modals stack โ€” open a modal from inside another, any depth. Each new modal sits above the previous, only one backdrop dims the screen, and Esc / overlay-click affect only the topmost. Without stackable a modal is exclusive: opening one closes any other open modal.

Vue SFC

Z-index โ€‹

By default the modal takes its stacking level from mono's shared popup stack, so the newest layer is always on top. Set z-index to pin it instead โ€” for sitting above (or below) something the host app already positions, like a sticky header or a third-party widget. The value is the overlay's level; the panel renders one above it. Accepts z-index="1500", :z-index="1500" and :zIndex="1500".

Vue SFC

Draggable โ€‹

Set draggable to let users move the modal by its header โ€” handy with stacked modals to slide the top one aside and see what's behind. The panel follows the pointer freely while dragging, but snaps back fully inside the viewport when you drop it.

Vue SFC

Colors โ€‹

All built-in color variants.

Vue SFC

Confirmation โ€‹

Cancel + Confirm footer that triggers a status update.

Vue SFC

Form โ€‹

Modal containing an input + submit button.

Vue SFC

Persistent โ€‹

Overlay-click and Escape do not close โ€” only the buttons or the โœ• work.

Vue SFC

No overlay โ€‹

Page behind stays interactive.

Vue SFC

Event log โ€‹

The modal emits mno-click on every state change, plus mno-open (on open) and mno-close (on close) โ€” matching the drawer. Each event's detail.source (overlay / close / escape / manual) says what triggered it. The log below shows the close events and their source.

Vue SFC

Customized โ€‹

Override per-element styling with cssClass (Vue) or utility classes (CSS).

Vue SFC

CSS Variables โ€‹

Vue SFC

Every modal is themed through --mono-modal-* custom properties. Because the dialog renders through a <body> portal, --mono-modal-* set inline on the <mono-modal> element are forwarded to the portal (so per-instance theming works); you can also set them on :root to theme every modal, and they pierce the shadow-DOM boundary for the shadow build. The size and color props set presets, but an explicit --mono-modal-* override always wins. To re-skin globally, set the underlying --theme-* tokens.

VariableDefaultControls
--mono-modal-accent--theme-primaryHeader tint, title, close-hover, scrollbar (set by color)
--mono-modal-bg--theme-surfacePanel background
--mono-modal-text--theme-textPanel text color
--mono-modal-border--theme-borderPanel + head/foot border
--mono-modal-head-bgaccent 10%Header gradient base
--mono-modal-radius18pxPanel corner radius (set by size)
--mono-modal-pad-x1.4remHead / body / foot horizontal padding (set by size)
--mono-modal-head-pad-y1.1remHeader vertical padding (set by size)
--mono-modal-foot-pad-y0.9remFooter vertical padding (set by size)
--mono-modal-title-font--theme-title-font-lgTitle font size (set by size)
--mono-modal-body-font--theme-subtitle-font-lgBody font size (set by size)
--mono-modal-close-size28pxClose-button box (set by size)
--mono-modal-widthmin(90vw,520px)Panel width โ€” not set by size; use the width prop
--mono-modal-overlay-bgrgba(15,48,96,.45)Backdrop scrim color
--mono-modal-shadowaccent glowPanel shadow
--mono-modal-z600Base z-index (the popup stack overwrites this per level; prefer the z-index prop, and note an inline var still wins over it)

Types โ€‹

Importimport { ModalProps } from 'mono-helper'
PropValueDefaultDescription
modelValuebooleanโ€”Open state, two-way bound for v-model-style usage.
size'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'โ€”Width preset of the modal panel.
color'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info'โ€”Theme color applied to accents.
titlestringโ€”Heading text shown in the modal header.
dismissiblebooleanโ€”Shows the close button and allows dismissal.
persistentbooleanโ€”Prevents closing via overlay click or escape.
overlaybooleanโ€”Renders a backdrop overlay behind the panel.
closeOnEscapebooleanโ€”Closes the modal when the Escape key is pressed.
closeOnOverlaybooleanโ€”Closes the modal when the overlay is clicked.
lockScrollbooleanโ€”Locks body scroll while the modal is open.
draggablebooleanโ€”Allow dragging the modal by its header; it snaps back inside the viewport on drop.
autoFullscreen'sm' | 'md' | 'lg' | 'xl' | '2xl' | booleanโ€”Fill the screen at a breakpoint and below (default `false`). `auto-fullscreen` on its own means Tailwind's `sm` (< 640px); a token moves the boundary, so `auto-fullscreen="lg"` covers everything `lg:` does not match (< 1024px).
stackablebooleanโ€”Allow this modal to stack on top of others. When false (default) it is exclusive โ€” opening it closes any other open modals.
widthstring | numberโ€”Explicit panel sizing. Each accepts a CSS length string (`"12px"`, `"12rem"`, `"80%"`) or a number / numeric string (interpreted as px). Set both `width` and `height` to `"100%"` for true full-screen.
heightstring | numberโ€”โ€”
minWidthstring | numberโ€”โ€”
maxWidthstring | numberโ€”โ€”
minHeightstring | numberโ€”โ€”
maxHeightstring | numberโ€”โ€”
zIndexstring | numberโ€”Pin the modal to an explicit stacking level. Unset (the default) lets the shared popup stack assign one so the newest layer is always on top. The value is the overlay's `z-index`; the panel sits one above it.
cssClassModalCssClassโ€”Per-part class overrides for internal elements.
cssClassNamestringโ€”Plain root class string applied to the modal.