@minspa/modal
v0.0.3
Published
A vanilla UI modal service module.
Downloads
12
Readme
Minspa Modal
A lightweight UI modal service with bootstrap like styling. This is a standalone component of the Minspa framework, and can be used independently, or with the framework.
About Bootstrap styling:
- This component does not depend on bootstrap - it includes a hardcoded subset of the stlyes needed to give it the bootstrap styled look.
- Modals are rendered in a shadow dom, to ensure no conflicts with any styles used in the main SPA project. The SPA project may choose to use bootstrap styling in it's entiretly, or some comletely different styling.
Minspa is a modern lightweight UI SPA framework.
- Modular - Written as ES modules, supported by all modern browsers.
- Depencency free - No nested dependencies.
- Vanilla - Components can be cloned and used as-is, directly within your project without the need for bundling.
Installation and Usage
For NodeJS projects
Installation
In your project directory, install the dependency on the command line:
npm install --save @minspa/modalUsage
Import the package in your code:
import { modalSvc } from '@minspa/modal'For Vanila projects
Vanilla Installation
Clone MinspaModal.js into your project.
Vanilla Usage
From an ES module, import the package in your code:
import { modalSvc } from '<path/to/>MinspaModal.js'Overview
A lightweight, dependency-free modal service for vanilla JavaScript applications for displaying informational, confirmation, and loader/busy modals.
Key Features
- Shadow DOM Encapsulation - Styles are isolated and won't conflict with your app
- Modal Queuing - Multiple modals are automatically queued and displayed sequentially
- Promise-based API - Modern async/await support
- Smart Loader - Delays to avoid flickering, one loader for multiple async operations
- Zero Dependencies - Pure vanilla JavaScript
Sample Screenshots
Confirmation modal:

Loader:

API Reference
okModal(body, options)
Display a modal with only an OK button. Returns a promise that resolves when OK is clicked.
Parameters:
body(string) - HTML content for the modal bodyoptions(object, optional)title(string) - Modal title (header hidden if not provided)okLabel(string) - Custom OK button text (default: "OK")sanitizer(function) - Function to sanitize HTML content
Returns:
Promise- resolves to true
- includesclose() method, enables closing the modal programatically without user input
Example:
await modalSvc.okModal('Operation completed successfully!')
// With options
await modalSvc.okModal(
'<p>Your changes have been saved.</p>',
{
title: 'Success',
okLabel: 'Great!',
sanitizer: DOMPurify.sanitize
}
)okCancelModal(body, options)
Display a modal with OK and Cancel buttons. Returns a promise that resolves to true/false based on user selection. Supports an onOk callback to extract data from the modal before it closes.
Parameters:
body(string) - HTML content for the modal bodyoptions(object, optional)title(string) - Modal titleokLabel(string) - Custom OK button text (default: "OK")cancelLabel(string) - Custom Cancel button text (default: "Cancel")sanitizer(function) - Function to sanitize HTML contentonOk(function) - Callback executed when OK is clicked, receives the modal element as parameter
Returns:
Promise- resolves to true/false based on user selection
- includes close() method, enables closing the modal programatically without user input
Example:
const confirmed = await modalSvc.okCancelModal(
'Are you sure you want to delete this item?',
{
title: 'Confirm Delete',
okLabel: 'Delete',
cancelLabel: 'Keep'
}
)
if (confirmed) {
// User clicked OK/Delete
deleteItem()
} else {
// User clicked Cancel/Keep
console.log('Deletion cancelled')
}showLoader()
Display a loading spinner modal. Returns a callback function to close the loader.
Features:
- Delayed Display: Loader only shows after 500ms to avoid flickering for fast operations
- Reference Counting: Multiple calls stack, loader closes when all are resolved
- Auto-queuing: Waits for other modals to close first
Returns: Function (call to close the loader)
Example:
// Basic usage
const closeLoader = modalSvc.showLoader()
await fetchData()
closeLoader()
// Multiple async operations - one loader displays until all async logic done
const fetchData = async query => {
const closeLoader = modalSvc.showLoader()
try {
return await dbSelect(query)
} finally {
closeLoader()
}
}
const [result1, result2] = await Promise.all([fetchData(q1), fetchData(q2)])Advanced Examples
Adding Custom Styles
The modal service supports adding custom styles globally using the addStyles() method. This is particularly useful for styling form controls or other elements within modals.
// Add custom styles for form inputs
modalSvc.addStyles(/* css */`
.form-control {
width: 100%;
padding: 8px;
border: 1px solid #ced4da;
border-radius: 4px;
}
`)Note: Adding styles via addStyles() applies them globally to all modals and is the recommended approach, especially when using Content Security Policy (CSP) headers. While you can include styles directly in the modal body HTML, that approach requires unsafe-inline CSP permissions.
Using onOk Callback to Extract Modal Data
The okCancelModal supports an onOk callback that executes when the user clicks OK, allowing you to extract data from the modal before it closes:
const inputModalBody = /* html */ `
<p>Please enter some data:</p>
<input type="text" id="userInput" class="form-control" placeholder="Type something...">
`
let userInputValue = ''
const onOkCallback = (modalElement) => {
// Extract the input value from the modal
const inputField = modalElement.querySelector('#userInput')
userInputValue = inputField?.value || ''
}
const result = await modalSvc.okCancelModal(inputModalBody, {
title: 'User Input',
onOk: onOkCallback
})
if (userInputValue) {
// Use the extracted value
await modalSvc.okModal(`<p>You entered: <strong>${userInputValue}</strong></p>`, {
title: 'Your Input'
})
}Programmatic Modal Closing
const okModal = modalSvc.okModal('This is an OK-only modal!', { title: 'Information' })
// auto close after 5s timer
const { promise: timeoutPromise, resolve } = Promise.withResolvers()
const timeoutId = setTimeout(() => { okModal.close(); resolve() }, 5000)
// wait for 5 seconds or user input, whatever comes first
await Promise.race([okModal, timeoutPromise])
try { clearTimeout(timeoutId) } catch {} // clear timeout if user beat the timer
Sequential Modals (Auto-queued)
// These will display one after another automatically
modalSvc.okModal('Step 1 complete')
modalSvc.okModal('Step 2 complete') // won't display until first modal closed
modalSvc.okModal('All done!')Content Sanitization
Using DOMPurify as a sample sanitizer:
import DOMPurify from 'dompurify'
const userInput = '<img src=x onerror=alert(1)>'
// Sanitize untrusted content
await modalSvc.okModal(userInput, {
title: 'User Message',
sanitizer: DOMPurify.sanitize
})License
MIT License - See notice in source code comments.
