@get-set/gs-modal
v1.0.2
Published
Get-Set Modal
Maintainers
Readme
@get-set/gs-modal
A dependency-free, fully accessible (WAI-ARIA) modal / dialog / alert / lightbox plugin available in two flavours from one codebase:
- Native / vanilla JS — a
window.GSModal(selector, params)factory (also exposed as a jQuery plugin and anHTMLElement.prototypemethod), plus SweetAlert-styleGSModal.fire / alert / confirm / promptstatics. - React — a
<GSModal />forwardRefcomponent that renders through a portal todocument.body, plusgsFire / gsAlert / gsConfirm / gsPromptPromise helpers.
Both surfaces drive one shared core (actions/, constants/, helpers/,
types/), so behaviour is identical across the two — every option works in
both targets (except the few tagged React-only / native-only below).
Features
- 17-entry animation catalog —
fade,zoom/scale,slide-down,slide-up,slide-left,slide-right,flip-x,flip-y,rotate,fall,sticky-up,newspaper,door,blur,bounce,none. SeparateexitAnimationand an independently animated backdrop. - Backdrop primitives + rich layer catalog — color / opacity / blur
primitives plus a
backdropTypecatalog:gradient,vignette,glass,aurora(animated shifting gradient),liquid(animated flowing blobs). - 13 position presets —
center, edges, and RTL-aware*-start/*-endcorners, with a customoffset. - Sizes + explicit dimensions —
sm/md/lg/xl, pluswidth/height/min*/max*. - Full-screen + responsive full-screen (
fullscreen,fullscreenBelow). - Focus trap + return focus, body scroll lock with scrollbar-gap compensation, and modal stacking (auto z-index layering).
- Content modes — remote
urlfetch, embeddediframe, imagelightbox, and a loading spinner. - SweetAlert-style presets — animated icons (
success/error/warning/info/question), confirm/cancel buttons, and Promise-basedfire. autoClosetimer with a depleting progress bar and pause-on-hover.draggableby header,persistent(non-dismissable), and'static'backdrop with a shake on blocked clicks.- Light / dark / auto theming, RTL,
prefers-reduced-motionhonored, per-partcustomClassoverrides, and a React-only scoped-stylesgsxprop.
Compatibility
| Target | Requirement |
|---|---|
| React (the <GSModal> component) | React 16.8+ (Hooks + forwardRef), and 17 / 18 / 19. React is an optional peer dependency — you only need it for the component. The React preset helpers (gsFire …) use react-dom/client (React 18+). |
| Native / vanilla (window.GSModal) | No framework. Any modern evergreen browser. Optional jQuery ($(...).GSModal(...)) and HTMLElement.prototype.GSModal(...) adapters are registered automatically by the bundle. |
| TypeScript | First-class — type declarations (.d.ts) ship in the package. |
| SSR / Next.js | Safe to import server-side (the portal is client-gated). The modal is browser-only, so render it inside a Client Component ('use client'). |
The peer range is
^16.8.0 || ^17.0 || ^18.0 || ^19.0, withreact/react-dommarked optional so the native build has zero dependencies.
Project layout
GSModal.ts # native entry (webpack -> dist-js/bundle.js, window global)
components/GSModal.tsx # React component (tsc -> dist/, npm entry)
components/presets.tsx # React gsFire/gsAlert/gsConfirm/gsPrompt helpers
actions/ # shared engine (init/open/close/animate/fire/focusTrap/…)
constants/ # animations, sizes, default params
helpers/ # layout, content, presets, draggable, ui helpers
types/ # Params / Ref / Window augmentation
components/styles/ # SCSS + compiled CSS + CSS-as-TS (runtime injection for React)
styles/ # SCSS + compiled CSS (for <link> use by the native build)Install
npm install @get-set/gs-modalBuild & test
npm install
npm run build # builds both targets
npm run build:js # native bundle -> dist-js/bundle.js
npm run build:react # React + types -> dist/
npm test # vitestSee example.html for a runnable native showcase exercising the animation
catalog, backdrop types, full-screen, positions, content modes, and presets.
Usage — Native JS
<button id="open-btn">Open modal</button>
<!-- content lives anywhere; the plugin lifts it into the overlay -->
<div id="my-modal" hidden>
<p>Hello from inside the modal.</p>
<button class="close">Close</button>
</div>
<link rel="stylesheet" href="node_modules/@get-set/gs-modal/styles/GSModal.css" />
<script src="node_modules/@get-set/gs-modal/dist-js/bundle.js"></script>
<script>
const modal = new GSModal('#my-modal', {
title: 'Greeting',
size: 'md',
animation: 'zoom',
trigger: '#open-btn',
closeHandler: '#my-modal .close',
afterOpen: () => console.log('opened')
});
// Imperative control:
// modal.openModal(); modal.closeModal(); modal.toggle(); modal.isOpen();
</script>Equivalent jQuery / element forms (registered by the bundle banner):
$('#my-modal').GSModal({ title: 'Hi' });
document.querySelector('#my-modal').GSModal({ title: 'Hi' });Instance methods (registry)
The factory registers each instance in the window.GSModalConfigue registry
(note the canonical misspelling). Look up an instance by its reference key:
new GSModal('#my-modal', { reference: 'main' });
const instance = window.GSModalConfigue.instance('main'); // -> the Ref
instance.openModal();
instance.closeModal();
window.GSModalConfigue.references; // [{ key, ref }, …]Usage — React
import React, { useRef } from 'react';
import GSModal, { GSModalHandle } from '@get-set/gs-modal';
function Example() {
const modal = useRef<GSModalHandle>(null);
return (
<>
<button onClick={() => modal.current?.open()}>Open</button>
<GSModal
ref={modal}
title="Greeting"
size="md"
animation="zoom"
onOpen={() => console.log('opened')}
onClose={() => console.log('closed')}>
<p>Hello from inside the modal.</p>
<button onClick={() => modal.current?.close()}>Close</button>
</GSModal>
</>
);
}Styles are injected at runtime — no CSS import required.
Controlled vs. uncontrolled
- Uncontrolled: omit
open. Drive it withdefaultOpen, the imperativeref, or atriggerelement. - Controlled: pass
open(and react toonOpen/onClose); the modal mirrors your state.
Next.js (App Router)
The modal is browser-only, so use it from a Client Component:
'use client';
import GSModal from '@get-set/gs-modal';
export default function Dialog() {
return (
<GSModal defaultOpen title="Hello" animation="bounce">
<p>Rendered through a portal to document.body.</p>
</GSModal>
);
}gsx — scoped styles (React-only)
The gsx prop injects a <style> scoped to the instance via the overlay's
data-key, and removes it on unmount:
<GSModal gsx={{ '.gs-modal-dialog': { borderRadius: '20px' } }}>…</GSModal>Options / props
Legend: N = native (new GSModal / factory / jQuery / prototype),
R = React component. All lengths accept a number (interpreted as px) or a
CSS string.
Identity
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| reference | string | auto (GUID) | ✓ | ✓ | Registry key / data-key. |
| open | boolean | — | | ✓ | Controlled open state (React). |
| defaultOpen | boolean | false | | ✓ | Uncontrolled initial open state (React). |
| gsx | NestedCSS | — | | ✓ | React-only scoped style object. |
Content & structure
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| title | string | — | ✓ | ✓ | Header title. Renders a header and sets aria-labelledby. |
| subtitle | string | — | ✓ | ✓ | Secondary line under the title. |
| text | string | — | ✓ | ✓ | Plain-text body (escaped). |
| html | string | — | ✓ | ✓ | Rich HTML body (raw, not escaped). |
| children | ReactNode | — | | ✓ | Inline body content (preferred in React). |
| footer | string \| false | false | ✓ | ✓ | Footer area content. false = no footer. |
| scrollable | boolean | true | ✓ | ✓ | Body scrolls independently; header & footer stay sticky. |
| stickyHeader | boolean | true | ✓ | ✓ | Pin the header while the body scrolls. |
| stickyFooter | boolean | true | ✓ | ✓ | Pin the footer while the body scrolls. |
Sizes & dimensions
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| size | 'sm' \| 'md' \| 'lg' \| 'xl' | 'md' | ✓ | ✓ | Width preset class (gs-modal-sm…xl). |
| width | number \| string | from size | ✓ | ✓ | Explicit width (overrides size, drops the size class). |
| height | number \| string | auto | ✓ | ✓ | Explicit height. |
| maxWidth | number \| string | 92vw | ✓ | ✓ | Clamp width on small viewports. |
| maxHeight | number \| string | 90vh | ✓ | ✓ | Clamp height; body becomes scrollable past this. |
| minWidth | number \| string | — | ✓ | ✓ | Lower bound on width. |
| minHeight | number \| string | — | ✓ | ✓ | Lower bound on height. |
Full-screen
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| fullscreen | boolean | false | ✓ | ✓ | Always full-viewport (no margins/rounding); disables drag. |
| fullscreenBelow | false \| 'sm' \| 'md' \| 'lg' \| 'xl' \| number | false | ✓ | ✓ | Full-screen when the viewport width ≤ breakpoint. number = px. |
Named breakpoints: sm=576, md=768, lg=992, xl=1200.
Position
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| position | GSModalPosition | 'center' | ✓ | ✓ | One of the 13 presets (see catalog). |
| offset | { x?: number\|string; y?: number\|string } | {0,0} | ✓ | ✓ | Custom nudge (CSS vars --gsm-offset-x/y). |
Backdrop
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| backdrop | boolean \| 'static' | true | ✓ | ✓ | true = dimmed, click-to-close. false = no overlay. 'static' = present but click does not close (plays a shake). |
| backdropColor | string | rgba(17,24,39,.55) | ✓ | ✓ | Overlay color (--gsm-backdrop-color). |
| backdropOpacity | number (0–1) | theme | ✓ | ✓ | Overlay opacity (--gsm-backdrop-opacity). |
| backdropBlur | boolean \| number \| string | false | ✓ | ✓ | Backdrop blur. true=8px; number=px; string=raw CSS (--gsm-backdrop-blur). |
| backdropType | GSModalBackdropType | — | ✓ | ✓ | Rich backdrop layer preset, layered on top of the primitives (see catalog). Applied as a gs-modal-bd-<type> class on the open overlay. |
Animation
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| animation | GSModalAnimation \| false | 'zoom' | ✓ | ✓ | Entrance animation (see catalog). false disables dialog motion. |
| exitAnimation | GSModalAnimation \| false | mirror of animation | ✓ | ✓ | Separate exit animation. |
| animationDuration | number \| { enter?: number; exit?: number } | 250 | ✓ | ✓ | Duration(s) in ms (--gsm-anim-duration). |
| animationEasing | string | cubic-bezier(.34,1.56,.64,1) | ✓ | ✓ | CSS easing (--gsm-anim-easing). |
| backdropAnimation | GSModalAnimation \| false | 'fade' | ✓ | ✓ | Backdrop's own animation (independent of the dialog). |
| backdropAnimationDuration | number | 200 | ✓ | ✓ | Backdrop fade duration in ms (--gsm-backdrop-duration). |
| reducedMotion | 'auto' \| boolean | 'auto' | ✓ | ✓ | 'auto' honors prefers-reduced-motion: reduce and falls back to no motion. |
Close affordances
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| closeOnBackdrop | boolean | true | ✓ | ✓ | Close when the backdrop is clicked. |
| closeOnEsc | boolean | true | ✓ | ✓ | Close on Escape (topmost modal only). |
| showClose | boolean | true | ✓ | ✓ | Show the built-in × close button. |
| closeButtonPosition | 'top-end' \| 'top-start' \| 'header' \| 'outside' | 'top-end' | ✓ | ✓ | Where the close button sits (RTL-aware). |
| closeHandler | string \| HTMLElement \| RefObject | — | ✓ | ✓ | In-content element(s) that close the modal on click. |
| returnFocus | boolean | true | ✓ | ✓ | Restore focus to the previously focused element on close. |
Behaviors
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| draggable | boolean | false | ✓ | ✓ | Drag the dialog by its header (disabled for fullscreen). |
| persistent | boolean | false | ✓ | ✓ | Non-dismissable: backdrop/Esc/× no longer close (only programmatic close). Plays a shake on blocked clicks. |
| autoClose | number \| false | false | ✓ | ✓ | Auto-close after N ms. |
| autoCloseProgress | boolean | true when autoClose | ✓ | ✓ | Show the depleting countdown progress bar. |
| pauseOnHover | boolean | true | ✓ | ✓ | Pause the autoClose countdown while the pointer is over the dialog. |
| lockScroll | boolean | true | ✓ | ✓ | Lock <body> scroll while open. |
| disableScroll | boolean | alias of lockScroll | ✓ | ✓ | Micromodal naming alias; overrides lockScroll when supplied. |
| scrollbarPadding | boolean | true | ✓ | ✓ | Compensate for scrollbar width when locking scroll (avoids layout shift). |
| trigger | string \| HTMLElement \| RefObject | — | ✓ | ✓ | Element(s) that open the modal on click. |
Content modes (dynamic)
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| url | string | — | ✓ | ✓ | Fetch remote HTML into the body; shows the loader until resolved. |
| iframe | string | — | ✓ | ✓ | Render an <iframe src> body sized to the dialog. |
| image | string | — | ✓ | ✓ | Image URL shown in the body (pairs with lightbox). |
| imageAlt | string | '' | ✓ | ✓ | Alt text for the image body. |
| lightbox | boolean | false | ✓ | ✓ | Borderless image-lightbox styling. |
| loading | boolean | false | ✓ | ✓ | Show the loading spinner immediately. |
| loaderHtml | string (N) / string \| ReactNode (R) | built-in spinner | ✓ | ✓ | Custom spinner content. |
Focus management
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| autofocus | boolean | true | ✓ | ✓ | Auto-focus the first focusable element (or [autofocus]) on open. |
| initialFocus | string \| HTMLElement \| RefObject \| false | — | ✓ | ✓ | Explicit element to focus. false focuses the dialog container. |
| disableFocus | boolean | false | ✓ | ✓ | Skip auto-focus entirely (Micromodal parity). |
The focus trap (Tab / Shift+Tab cycle) is always active inside the dialog while
open, and skips the built-in × button when other content is focusable.
Theming
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| theme | 'light' \| 'dark' \| 'auto' | 'auto' | ✓ | ✓ | Visual theme; auto follows prefers-color-scheme. |
| accentColor | string | brand | ✓ | ✓ | Accent for the focus ring / close button (--gsm-accent). |
| rtl | boolean | false | ✓ | ✓ | Right-to-left layout. |
| className | string | — | ✓ | ✓ | Extra class on the overlay root. |
| customClass | GSModalCustomClass | {} | ✓ | ✓ | Per-part class map (below). |
customClass keys: container, backdrop, popup, header, title,
subtitle, closeButton, body, footer, loader, image, progressBar,
icon, actions, confirmButton, cancelButton.
Accessibility
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| role | 'dialog' \| 'alertdialog' | 'dialog' | ✓ | ✓ | alertdialog for confirmations; presets default closeOnEsc/closeOnBackdrop to false. |
Always applied: tabindex="-1" + aria-modal="true" on the dialog,
aria-labelledby wired from title, aria-hidden toggling on the overlay,
focus trap + return focus, and prefers-reduced-motion honored.
Presets (alert / confirm)
| Name | Type | Default | N | R | Description |
| --- | --- | --- | :-: | :-: | --- |
| icon | 'success' \| 'error' \| 'warning' \| 'info' \| 'question' \| false | false | ✓ | ✓ | Built-in animated icon glyph. |
| iconColor | string | per-icon | ✓ | ✓ | Override the icon color (--gsm-icon-color). |
| showConfirm | boolean | false (true for presets) | ✓ | ✓ | Show the confirm button. |
| showCancel | boolean | false | ✓ | ✓ | Show the cancel button. |
| confirmText | string | 'OK' | ✓ | ✓ | Confirm label. |
| cancelText | string | 'Cancel' | ✓ | ✓ | Cancel label. |
| confirmColor | string | theme | ✓ | ✓ | Confirm button color (--gsm-btn-color). |
| cancelColor | string | theme | ✓ | ✓ | Cancel button color (--gsm-btn-color). |
| reverseButtons | boolean | false | ✓ | ✓ | Invert the cancel/confirm order. |
| onConfirm | (value?) => void | — | ✓ | ✓ | Confirm callback. |
| onCancel | (reason?) => void | — | ✓ | ✓ | Cancel callback (receives the dismissal reason). |
Lifecycle callbacks
| Name | Type | Cancelable | N | R | Description |
| --- | --- | :-: | :-: | :-: | --- |
| beforeOpen | () => void \| boolean | ✓ | ✓ | ✓ | Return false to abort opening. |
| afterOpen | () => void | — | ✓ | ✓ | After the open is set up (React-idiomatic alias: onOpen). |
| beforeClose | () => void \| boolean | ✓ | ✓ | ✓ | Return false to keep open. |
| afterClose | () => void | — | ✓ | ✓ | After the exit animation + teardown (React-idiomatic alias: onClose). |
| onOpen | () => void | — | | ✓ | React: fired after open (alias of afterOpen). |
| onClose | () => void | — | | ✓ | React: fired after close (alias of afterClose). |
Variant catalogs
Animation catalog
animation, exitAnimation, and backdropAnimation accept any of these names.
Each maps to a @keyframes gsm-<name>-in / gsm-<name>-out pair defined in all
CSS sources. The backdrop animates independently from the dialog (own name +
duration), so e.g. a fade-overlay + zoom-dialog can run together.
| Name | Motion |
| --- | --- |
| fade | Opacity in/out. |
| zoom | Scale 0.9 → 1 (the default). |
| scale | Alias of zoom (shares its keyframes). |
| slide-down | Enters from above. |
| slide-up | Enters from below. |
| slide-left | Enters from the right. |
| slide-right | Enters from the left. |
| flip-x | 3D flip about the X axis. |
| flip-y | 3D flip about the Y axis. |
| rotate | Spins into place. |
| fall | Drops in with perspective. |
| sticky-up | Slides up from the top edge. |
| newspaper | Spin + scale. |
| door | 3D door-style split. |
| blur | Blur-in / blur-out. |
| bounce | Springy overshoot. |
| none | No motion (the reduced-motion / disabled fallback). |
new GSModal('#m', {
animation: 'door',
exitAnimation: 'fade',
animationDuration: { enter: 320, exit: 160 },
backdropAnimation: 'fade',
backdropAnimationDuration: 200
});Backdrop type catalog
backdropType layers a rich effect on top of the backdrop /
backdropColor / backdropBlur primitives (applied as a gs-modal-bd-<type>
class on the open overlay). The aurora and liquid types animate; both fall
back to a static layer under prefers-reduced-motion.
| backdropType | Effect |
| --- | --- |
| gradient | Diagonal color gradient. |
| vignette | Darkened radial edges. |
| glass | Frosted translucent blur + saturation. |
| aurora | Animated shifting gradient. |
| liquid | Animated flowing color blobs. |
new GSModal('#m', { backdrop: true, backdropType: 'aurora', backdropBlur: true });Position catalog
position accepts any of these 13 presets. The *-start / *-end variants are
RTL-aware. Combine with offset for a custom nudge.
| Group | Values |
| --- | --- |
| Center | center |
| Edges | top, bottom, left, right |
| Top corners | top-start, top-end |
| Bottom corners | bottom-start, bottom-end |
| Left corners | left-start, left-end |
| Right corners | right-start, right-end |
Size catalog
| size | Class |
| --- | --- |
| sm | gs-modal-sm |
| md | gs-modal-md (default) |
| lg | gs-modal-lg |
| xl | gs-modal-xl |
Theme catalog
| theme | Behaviour |
| --- | --- |
| light | Forces the light palette. |
| dark | Forces the dark palette. |
| auto | Follows prefers-color-scheme (default). |
Animated preset icons
icon renders one of five built-in, CSS-animated glyphs, each with a default
semantic color you can override via iconColor:
| icon | Default color |
| --- | --- |
| success | #16a34a |
| error | #dc2626 |
| warning | #f59e0b |
| info | #3b82f6 |
| question | #6b7280 |
Content modes
// Remote HTML (loader shown until it resolves):
new GSModal('#m', { url: '/partials/help.html' });
// Embedded iframe:
new GSModal('#m', { iframe: 'https://example.com', width: 900, height: 600 });
// Image lightbox (borderless, transparent chrome):
new GSModal('#m', { image: '/photo.jpg', imageAlt: 'A photo', lightbox: true });
// Loading spinner immediately, then swap content in:
const ref = new GSModal('#m', { loading: true });
ref.openModal();
fetchData().then((html) => ref.setLoading(false).setContent(html));Presets — alert / confirm / prompt (Promise-based)
Native statics — GSModal.fire / alert / confirm / prompt
These create a transient modal, open it, and resolve a Promise<GSModalResult>.
const res = await GSModal.fire({
title: 'Save changes?',
text: 'Your edits will be lost otherwise.',
icon: 'warning',
showConfirm: true,
showCancel: true,
confirmText: 'Save',
cancelText: 'Discard'
});
if (res.isConfirmed) save();
await GSModal.alert('Done', 'All good', 'success'); // single OK
const c = await GSModal.confirm('Sure?', 'This cannot be undone.');
if (c.isConfirmed) remove();Signatures:
GSModal.fire(options)→Promise<GSModalResult>GSModal.alert(title, text?, icon?)→Promise<GSModalResult>GSModal.confirm(title, text?, options?)→Promise<GSModalResult>GSModal.prompt(title, options?)→Promise<GSModalResult>
React helpers — gsFire / gsAlert / gsConfirm / gsPrompt
import { gsConfirm, gsAlert } from '@get-set/gs-modal/dist/components/presets';
async function onDelete() {
const res = await gsConfirm('Delete item?', 'This cannot be undone.');
if (res.isConfirmed) {
await doDelete();
await gsAlert('Deleted', 'The item is gone.', 'success');
}
}GSModalResult:
interface GSModalResult {
isConfirmed: boolean;
isDismissed: boolean;
value?: unknown; // present when confirmed
dismiss?: 'cancel' | 'backdrop' | 'close' | 'esc' | 'timer';
}Preset modals default to role: 'alertdialog', which turns off closeOnEsc /
closeOnBackdrop (pass them explicitly to re-enable).
Imperative API
React GSModalHandle (via ref)
import GSModal, { GSModalHandle } from '@get-set/gs-modal';
import { useRef } from 'react';
const ref = useRef<GSModalHandle>(null);
// <GSModal ref={ref} …>…</GSModal>
ref.current?.open();| Method | Returns | Description |
| --- | --- | --- |
| open() | void | Open the modal. |
| close() | void | Close the modal. |
| toggle() | void | Toggle the open state. |
| isOpen() | boolean | Whether the modal is open. |
| setContent(node) | void | Replace the body content (string or node). |
| setLoading(on) | void | Toggle the loading spinner over the body. |
| isLoading() | boolean | Whether the spinner is shown. |
| clickConfirm() | void | Trigger the preset confirm action. |
| clickCancel() | void | Trigger the preset cancel action. |
Native instance
Returned by new GSModal(...) / the factory / GSModalConfigue.instance(key):
| Method | Returns | Description |
| --- | --- | --- |
| openModal() | void | Open the modal. |
| closeModal() | void | Close the modal. |
| toggle() | void | Toggle the open state. |
| isOpen() | boolean | Whether the modal is open. |
| refresh() | void | Rebuild the overlay from params. |
| destroy() | void | Tear down, restore content, unregister. |
| setContent(content) | this | Replace the body content (HTML string or element). |
| setLoading(on) | this | Toggle the loading spinner. |
| isLoading() | boolean | Whether the spinner is shown. |
| clickConfirm() | void | Click the preset confirm button. |
| clickCancel() | void | Click the preset cancel button. |
| getConfirmButton() | HTMLElement \| null | The preset confirm button. |
| getCancelButton() | HTMLElement \| null | The preset cancel button. |
Registry — window.GSModalConfigue
window.GSModalConfigue.references; // [{ key, ref }, …]
window.GSModalConfigue.instance('my-key'); // -> the Ref, or undefinedLicense
ISC.
