@js4y/dialog
v1.1.1
Published
A tiny dependency-free JavaSript ES6 library built on a dialog element with minimal configuration.
Downloads
47
Maintainers
Readme
Dialog
A tiny dependency-free javascript library built on a dialog element with minimal configuration, yet sufficiently variable.
Live Demo: https://bukacekd.github.io/dialog
Features
- closing the dialog using the
escape
key - closing the dialog by click on the backdrop or element with the corresponding data attribute
- loading external styles or attaching constructable stylesheets
- preventing scrolling of the page when displaying the dialog
- simple configuration and api
Installation
Npm
npm install @js4y/dialog
CDN
<script src="https://unpkg.com/@js4y/dialog/dist/index.js"></script>
Usage
Npm
import {Dialog} from '@js4y/dialog';
new Dialog({
content: 'Hello world!'
});
CDN
<script src="https://unpkg.com/@js4y/dialog/dist/index.js"></script>
<script>
new js4y.components.Dialog({
content: 'Hello world!'
});
<script>
Configuration
The library offers a set of configuration items. Below is an overview of them.
new Dialog({
className?: string,
close?: Function,
constructableSheets?: Array<CSSStyleSheet>,
content: string | AsyncFunction | Function | HTMLElement,
id?: string,
open?: Function,
styleSheets?: Array<string>
});
className
required: false
, type: string
CSS class of dialog.
new Dialog({
className: 'my-dialog'
});
id
required: false
, type: string
CSS Identifier of dialog. If you try to create multiple dialogs with the same identifier, only one will appear on the page - this prevents possible duplicates on the page.
const dialog1 = new Dialog({
id: 'my-dialog',
content: 'old content'
});
const dialog2 = new Dialog({
id: 'my-dialog',
content: 'new content'
});
dialog1 === dialog2;
According to the example above, only the dialog with the content "new-content" is displayed in the page.
content
required: true
, type: string
| AsyncFunction
| Function
| HTMLElement
The content that will be displayed.
new Dialog({
content: 'Hello <b>world</b>!'
});
new Dialog({
content: document.querySelector('template'),
});
new Dialog({
content: async (e, signal) => {
const response = await fetch('<url>', {signal}),
data = await response.text();
e.content(data);
}
});
The first parameter of the callback function corresponds to the dialog instance and the second to the AbortSignal object.
open
required: false
, type: Function
The function is fired when the dialog is opened. The function parameter corresponds to the dialog instance.
new Dialog({
open: dialog => console.log('opened', dialog)
});
close
required: false
, type: Function
The function is fired when the dialog is closed. The function parameter corresponds to the dialog instance.
new Dialog({
close: => console.log('closed', dialog)
});
constructableSheets
required: false
, type: Array<CSSStyleSheet>
List of constructable stylesheets. Can only be used if the browser supports constructable stylesheets and adoptedStyleSheets.
const sheet = new CSSStyleSheet();
sheet.replaceSync('<any style rules>');
new Dialog({
constructableSheets: [sheet]
});
If your browser supports import attributes, then you can use:
import sheet from '/dialog.css' with { type: 'css' };
new Dialog({
constructableSheets: [sheet]
});
styleSheets
required: false
, type: Array<string>
List of url addresses of external css styles. Styles are loaded asynchronously
new Dialog({
styleSheets: ['/dialog.css']
});
Styles can be loaded directly as dialog content.
new Dialog({
content: `
<link href="/dialog.css" rel="stylesheet">
Hello <b>world</b>!
`
});
In both cases, the dialog only appears when all css styles are loaded or fail to load.
Properties
element: HTMLDialogElement
An instance of the dialog element on the page.
new Dialog({
content: async e => {
await e.content('<button data-dialog-action="close">close</button>');
e.element.querySelector('button').addEventListener('click', () => {
console.log('was clicked');
});
}
});
Methods
abort()
Cancels the display of the dialog if its content is loaded by the fetch api extended by AbortSignal and has not yet been displayed.
const dialog = new Dialog({
content: async (e, signal) => {
const response = await fetch('<url>', {signal}),
data = await response.text();
e.content(data);
}
});
dialog.abort();
open(delay?: number): Promise
Opens the dialog immediately or with a delay.
dialog.open();
close(delay?: number): Promise
Close the dialog immediately or with a delay.
dialog.close(3000);
content(value: string | AsyncFunction | Function | HTMLElement, delay?: number): Promise
Changes the content of the dialog - immediately or with a delay.
dialog.content('🎉');
The use of the method can be useful in the case of displaying the loader during a long-running request.
new Dialog({
content: async (e, signal) => {
e.content('please wait...');
const response = await fetch('<url>', {signal}),
data = await response.text();
await e.content(data);
}
});
resolve(value?: any): Promise
Executes the callback function of then
method. The then
method is always executed only once regardless of the number of calls to the resolve
method.
dialog.resolve('😀');
reject(reason?: any): Promise
Executes the callback function of catch
method. The catch
method is always executed only once regardless of the number of calls to the reject
method.
dialog.reject('😢');
then(callback: AsyncFunction | Function
): Dialog
Callback function that is executed after calling the resolve
method.
dialog.then(value => console.log(value));
dialog.resolve('😀');
catch(callback: AsyncFunction | Function
): Dialog
Callback function that is executed after calling the catch
method.
dialog.catch(reason => console.log(reason));
dialog.reject('😢');
Actions
Html elements inside the dialog can call some methods - the prerequisite is the existence of the corresponding data attribute:
| Selector | Description |
| - | - |
| [data-dialog-action="close"]
| Closes the dialog. |
| [data-dialog-state="resolve"]
| Executes the callback function of then
method. |
| [data-dialog-state="reject"]
| Executes the callback function of reject
method. |
Actions can be combined with each other.
new Dialog({
content: `
Are you sure?
<button data-dialog-action="resolve close">Yes</button>
<button data-dialog-action="reject close">No</button>
`
})
.then(() => console.log('resolve'))
.catch(() => console.log('reject'));
Styling
By default, the dialog cannot be closed by clicking on the backdrop. However, this can be easily changed by adding the css style below to your application.
dialog::backdrop {
pointer-events: none;
}
The dialog does not contain any styles, except for the basic styles specific to each browser. Two css selectors are available for animation purposes:
| Selector | Description |
| - | - |
| [data-dialog-state="open"]
| State indicating the opening of a dialog. |
| [data-dialog-state="close"]
| State indicating the closing of a dialog. |
Examples of animated dialogs:
dialog,
dialog::backdrop {
opacity: 0;
transition: opacity .3s;
}
[data-dialog-state="open"],
[data-dialog-state="open"]::backdrop {
opacity: 1;
}
// or
dialog {
translate: 0 15%;
}
dialog,
dialog::backdrop {
opacity: 0;
transition: opacity .3s, translate .3s;
}
[data-dialog-state="open"],
[data-dialog-state="open"]::backdrop {
opacity: 1;
translate: none;
}
[data-dialog-state="close"] {
translate: 0 -15%;
}
Browser support
| | | | | | | :-: | :-: | :-: | :-: | :-: | | Chrome 84+ | Edge 84+ | Firefox 98+ | Opera 70+ | Safari 15.4+ |
License
The project is licensed under MIT license.
Related
- CountUp - A tiny dependency-free JavaSript library for animating numeric values.
- Loader - A tiny dependency-free javascript loading spinner component with minimal configuration.
- lockScroll - A set of methods to lock scrolling within an element or an entire page.