PNotify is a JavaScript notification and confirmation/prompt library. PNotify can provide desktop notifications based on the Web Notifications spec with fall back to an in-browser notice.
PNotify implements a unique notification flow called modalish that provides a good user experience, even when many notifications are shown at once.
Demos
Table of Contents
Getting Started
You can get PNotify using NPM. (You can also use jsDelivr or UNPKG.)
npm install --save pnotify
npm install --save material-design-icons
npm install --save animate.css
npm install --save nonblockjs
Inside the pnotify package:
src
Svelte components and uncompressed CSS.dist
compressed CSS and UMD modules.dist/es
compressed ECMAScript modules.
Installation
In addition to the JS and CSS, be sure to include a PNotify style.
Svelte
PNotify in Svelte. (Use the source files.)
import { alert, defaultModules } from 'pnotify/src/PNotify.svelte';
import * as PNotifyMobile from 'pnotify/src/PNotifyMobile.svelte';
defaultModules.set(PNotifyMobile, {});
alert('Notice me, senpai!');
React
PNotify in React.
import { alert, defaultModules } from 'pnotify/dist/PNotify.js';
import 'pnotify/dist/PNotify.css';
import * as PNotifyMobile from 'pnotify/dist/PNotifyMobile.js';
import 'pnotify/dist/PNotifyMobile.css';
defaultModules.set(PNotifyMobile, {});
alert('Notice me, senpai!');
Angular
PNotify in Angular.
import { alert, defaultModules } from 'pnotify/dist/PNotify.js';
import 'pnotify/dist/PNotify.css';
import * as PNotifyMobile from 'pnotify/dist/PNotifyMobile.js';
import 'pnotify/dist/PNotifyMobile.css';
defaultModules.set(PNotifyMobile, {});
export class WhateverComponent {
constructor() {
alert('Notice me, senpai!');
}
}
For IE support, see this issue.
Angular (Injectable)
PNotify in Angular as an injectable service.
import { Injectable } from '@angular/core';
import { alert, defaultModules } from 'pnotify/dist/PNotify.js';
import 'pnotify/dist/PNotify.css';
import * as PNotifyMobile from 'pnotify/dist/PNotifyMobile.js';
import 'pnotify/dist/PNotifyMobile.css';
defaultModules.set(PNotifyMobile, {});
@Injectable()
export class PNotifyService {
getPNotifyAlert() {
return alert;
}
}
import { PNotifyService } from './pnotify.service';
@NgModule({
declarations: [...],
imports: [...],
providers: [PNotifyService],
bootstrap: [...]
})
export class WhateverModule {}
import { PNotifyService } from './pnotify.service';
export class WhateverComponent {
alert = undefined;
constructor(pnotifyService: PNotifyService) {
this.alert = pnotifyService.getPNotifyAlert();
this.alert('Notice me, senpai!');
}
}
AngularJS
PNotify in AngularJS.
<link href="node_modules/pnotify/dist/PNotify.js" rel="stylesheet" type="text/css" />
<link href="node_modules/pnotify/dist/PNotifyMobile.js" rel="stylesheet" type="text/css" />
var angular = require('angular');
var PNotify = require('pnotify/dist/PNotify.js');
var PNotifyMobile = require('pnotify/dist/PNotifyMobile.js');
PNotify.defaultModules.set(PNotifyMobile, {});
angular.module('WhateverModule', [])
.value('PNotify', PNotify)
.controller('WhateverController', ['PNotify', function(PNotify) {
PNotify.alert('Notice me, senpai!');
}]);
Vanilla JS (ES5)
PNotify in vanilla ECMAScript 5.
<script type="text/javascript" src="node_modules/pnotify/dist/PNotify.js"></script>
<link href="node_modules/pnotify/dist/PNotify.js" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="node_modules/pnotify/dist/PNotifyMobile.js"></script>
<link href="node_modules/pnotify/dist/PNotifyMobile.js" rel="stylesheet" type="text/css" />
<script type="text/javascript">
PNotify.defaultModules.set(PNotifyMobile, {});
PNotify.alert('Notice me, senpai!');
</script>
Vanilla JS (ES6)
PNotify in vanilla ECMAScript 6+. (Use the ES modules from dist/es
.)
<link href="node_modules/pnotify/dist/PNotify.js" rel="stylesheet" type="text/css" />
<link href="node_modules/pnotify/dist/PNotifyMobile.js" rel="stylesheet" type="text/css" />
<script type="module">
import { alert, defaultModules } from 'node_modules/pnotify/dist/es/PNotify.js';
import * as PNotifyMobile from 'node_modules/pnotify/dist/es/PNotifyMobile.js';
defaultModules.set(PNotifyMobile, {});
alert('Notice me, senpai!');
</script>
Styles
Bright Theme
The default, standalone theme, Bright Theme. Supports dark mode. Include the CSS file in your page:
<link href="node_modules/pnotify/dist/PNotifyBrightTheme.css" rel="stylesheet" type="text/css" />
Or if you're using a packager that imports CSS:
import 'pnotify/dist/PNotifyBrightTheme.css';
Material
The Material style. Supports dark mode. Requires material-design-icons. Include the CSS file in your page:
<link href="node_modules/pnotify/dist/PNotifyMaterial.css" rel="stylesheet" type="text/css" />
Or if you're using a packager that imports CSS:
import 'pnotify/dist/PNotifyMaterial.css';
Then set the default styling and icons to 'material':
import { defaults } from 'pnotify/dist/PNotify.js';
const { defaults } = require('pnotify/dist/PNotify.js');
defaults.styling = 'material';
defaults.icons = 'material';
Material Icons
To use the Material Style icons, include the Material Design Icons Font in your page.
npm install --save material-design-icons
npm install --save material-design-icon-fonts
<link rel="stylesheet" href="node_modules/material-design-icons/iconfont/material-icons.css" />
Or if you're using a packager that imports CSS:
import 'material-design-icons/iconfont/material-icons.css';
Alternatively, you can use the Google Fonts CDN:
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons" />
Or a clone from jsDelivr:
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/material-icons-font@2.0.0/material-icons-font.css" />
Bootstrap
Styling for the popular Bootstrap library. Doesn't support dark mode (but you can use a Bootstrap theme).
Include the CSS:
<link rel="stylesheet" href="node_modules/pnotify/dist/PNotifyBootstrap4.css" />
Or if you're using a packager that imports CSS:
import 'pnotify/dist/PNotifyBootstrap4.css';
Include the appropriate line(s) from below:
import { defaultModules } from 'pnotify/dist/PNotify.js';
import * as PNotifyBootstrap4 from 'pnotify/dist/PNotifyBootstrap4.js';
const { defaultModules } = require('pnotify/dist/PNotify.js');
const PNotifyBootstrap4 = require('pnotify/dist/PNotifyBootstrap4.js');
Then set it as a default module:
defaultModules.set(PNotifyBootstrap4, {});
Change the "4" to "3" for Bootstrap 3, and also import and set PNotifyGlyphicon
to use Bootstrap 3's glyphicons. PNotifyGlyphicon
doesn't have any CSS to import.
Font Awesome 4 (Icons)
To set Font Awesome 4 as the default icons, include the appropriate line from below:
import { defaultModules } from 'pnotify/dist/PNotify.js';
import * as PNotifyFontAwesome4 from 'pnotify/dist/PNotifyFontAwesome4.js';
const { defaultModules } = require('pnotify/dist/PNotify.js');
const PNotifyFontAwesome4 = require('pnotify/dist/PNotifyFontAwesome4.js');
Then set it as a default module:
defaultModules.set(PNotifyFontAwesome4, {});
Font Awesome 5 (Icons)
To set Font Awesome 5 as the default icons, include the appropriate line from below:
import { defaultModules } from 'pnotify/dist/PNotify.js';
import * as PNotifyFontAwesome from 'pnotify/dist/PNotifyFontAwesome.js';
import * as PNotifyFontAwesome5 from 'pnotify/dist/PNotifyFontAwesome5.js';
const { defaultModules } = require('pnotify/dist/PNotify.js');
const PNotifyFontAwesome = require('pnotify/dist/PNotifyFontAwesome.js');
const PNotifyFontAwesome5 = require('pnotify/dist/PNotifyFontAwesome5.js');
Then set them as default modules:
defaultModules.set(PNotifyFontAwesome, {});
defaultModules.set(PNotifyFontAwesome5, {});
If you don't want to use Font Awesome 5 as your default icons, but you still want support for them in your notices, you should include only the PNotifyFontAwesome
module. They do some mysterious magic in their code that breaks PNotify. This module has a workaround for it.
Creating Notices
To make a notice, use the factory functions. Each one takes an options object as its only argument. It will return a PNotify notice instance.
import { alert, notice, info, success, error } from 'PNotify/dist/PNotify.js';
const { alert, notice, info, success, error } = require('pnotify/dist/PNotify.js');
const myAlert = alert({
text: "I'm an alert.",
type: 'info'
});
const myNotice = notice({
text: "I'm a notice."
});
const myInfo = info({
text: "I'm an info message."
});
const mySuccess = success({
text: "I'm a success message."
});
const myError = error({
text: "I'm an error message."
});
Options
PNotify options and default values.
defaults = {
type: 'notice'
Type of the notice. 'notice', 'info', 'success', or 'error'.title: false
The notice's title. Can be a string, an element, or false
for no title.titleTrusted: false
Whether to trust the title or escape its contents. (Not allow HTML.)text: false
The notice's text. Can be a string, an element, or false
for no text.textTrusted: false
Whether to trust the text or escape its contents. (Not allow HTML.)styling: 'brighttheme'
What styling classes to use. (Can be 'brighttheme', 'material', or a styling object.) (Note that the Bootstrap modules provide a different default.)icons: 'brighttheme'
What icons classes to use (Can be 'brighttheme', 'material', or an icon object.) (Note that the Font Awesome and Glyphicon modules provide a different default.)mode: 'no-preference'
Light or dark version of the theme, if supported by the styling. This overrides the CSS media query when a preference is given. (Can be 'no-preference', 'light', or 'dark'.)addClass: ''
Additional classes to be added to the notice. (For custom styling.)addModalClass: ''
Additional classes to be added to the notice, only when in modal.addModelessClass: ''
Additional classes to be added to the notice, only when in modeless.autoOpen: true
Open the notice immediately when it is created.width: '360px'
Width of the notice.minHeight: '16px'
Minimum height of the notice. It will expand to fit content.maxTextHeight: '200px'
Maximum height of the text container. If the text goes beyond this height, scrollbars will appear. Use null to remove this restriction.icon: true
Set icon to true to use the default icon for the selected style/type, false for no icon, or a string for your own icon class.animation: 'fade'
The animation to use when displaying and hiding the notice. 'none' and 'fade' are supported through CSS. Others are supported through the Animate module and Animate.css.animateSpeed: 'normal'
Speed at which the notice animates in and out. 'slow', 'normal', or 'fast'. Respectively, 400ms, 250ms, 100ms.shadow: true
Display a drop shadow.hide: true
After a delay, close the notice.delay: 8000
Delay in milliseconds before the notice is closed.mouseReset: true
Reset the hide timer if the mouse moves over the notice.closer: true
Provide a button for the user to manually close the notice.closerHover: true
Only show the closer button on hover.sticker: true
Provide a button for the user to manually stick the notice.stickerHover: true
Only show the sticker button on hover.labels: {close: 'Close', stick: 'Stick', unstick: 'Unstick'}
Lets you change the displayed text, facilitating internationalization.remove: true
Remove the notice's elements from the DOM after it is closed.destroy: true
Whether to remove the notice from the stack (and therefore, stack history) when it is closed.stack: defaultStack
The stack on which the notices will be placed. Also controls the direction the notices stack.modules: defaultModules
This is where modules and their options should be added. It is a map of module => options
entries.
}
defaultStack = new Stack({
dir1: 'down',
dir2: 'left',
firstpos1: 25,
firstpos2: 25,
spacing1: 36,
spacing2: 36,
push: 'bottom',
context: document.body
})
Learn more about stacks.
defaultModules = new Map()
Changing Defaults
import { defaults } from 'PNotify/dist/PNotify.js';
const { defaults } = require('pnotify/dist/PNotify.js');
defaults.width = '400px';
Adding/removing a module to the defaults:
import { defaultModules } from 'PNotify/dist/PNotify.js';
import * as PNotifyMobile from 'PNotify/dist/PNotifyMobile.js';
const { defaultModules } = require('pnotify/dist/PNotify.js');
const PNotifyMobile = require('pnotify/dist/PNotifyMobile.js');
defaultModules.set(PNotifyMobile, {});
defaultModules.delete(PNotifyMobile);
Changing a module's defaults:
import { defaults } from 'PNotify/dist/PNotifyAnimate.js';
const { defaults } = require('pnotify/dist/PNotifyAnimate.js');
defaults.inClass = 'fadeInDown';
defaults.outClass = 'fadeOutUp';
Modules
Creating Notices with Modules
Besides using the default modules, you can remove or add modules and set their options when you call a notice. The modules Map has modules themselves as keys, and an options object as values.
import { notice, defaultModules } from 'PNotify/dist/PNotify.js';
import * as PNotifyBootstrap4 from 'PNotify/dist/PNotifyBootstrap4.js';
import * as PNotifyFontAwesome4 from 'PNotify/dist/PNotifyFontAwesome4.js';
import * as PNotifyMobile from 'PNotify/dist/PNotifyMobile.js';
import * as PNotifyAnimate from 'PNotify/dist/PNotifyAnimate.js';
defaultModules.set(PNotifyBootstrap4, {});
defaultModules.set(PNotifyFontAwesome4, {});
defaultModules.set(PNotifyMobile, {});
notice({
text: "I don't have the PNotifyMobile module.",
modules: new Map([
...[...defaultModules].filter(([mod]) => mod !== PNotifyMobile)
])
});
notice({
text: "I use the PNotifyAnimate module in addition to the defaults.",
modules: new Map([
...defaultModules,
[PNotifyAnimate, {
inClass: 'fadeInDown',
outClass: 'fadeOutUp'
}]
])
});
notice({
text: "I use the PNotifyMobile module with options I specify.",
modules: new Map([
...defaultModules,
[PNotifyMobile, {
swipeDismiss: false
}]
])
});
Desktop Module
Notifications that display even when the web page is not visible. Implements the Web Notifications spec.
If the user's browser doesn't support Web Notifications, or they deny permission to show them, they will see regular in-browser notices, unless fallback
is false.
defaults = {
fallback: true
If desktop notifications are not supported or allowed, fall back to a regular notice.icon: null
The URL of the icon to display. If false, no icon will show. If null, a default icon will show.tag: null
Using a tag lets you update an existing notice, or keep from duplicating notices between tabs. If you leave tag null, one will be generated, facilitating the update
function.title: null
Optionally display a different title for the desktop.text: null
Optionally display different text for the desktop.options: {}
Any additional options to be passed to the Notification constructor.
}
Mobile Module
Notices on mobile phones and tablets.
defaults = {
swipeDismiss: true
Let the user swipe the notice away.
}
Animate Module
Fluid CSS animations using Animate.css.
defaults = {
inClass: null
The class to use to animate the notice in. If only one of these is set, it will be used for both.outClass: null
The class to use to animate the notice out. If only one of these is set, it will be used for both.
}
The Animate module also creates a method, attention(aniClass, callback)
, on notices which accepts an attention grabber class and an animation completed callback.
Confirm Module
Confirmation dialogs and prompts.
defaults = {
confirm: false
Make a confirmation box.focus: null
For confirmation boxes, true means the first button or the button with promptTrigger will be focused, and null means focus will change only for modal notices. For prompts, true or null means focus the prompt. When false, focus will not change.prompt: false
Make a prompt.promptClass: ''
Classes to add to the input element of the prompt.promptValue: ''
The value of the prompt. (Note that this is two-way bound to the input.)promptMultiLine: false
Whether the prompt should accept multiple lines of text.align: 'flex-end'
Where to align the buttons. (flex-start, center, flex-end, space-around, space-between)
buttons: [
{
text: 'Ok',
textTrusted: false,
addClass: '',
primary: true,
promptTrigger: true,
click: (notice, value) => {
notice.close();
notice.fire('pnotify:confirm', {notice, value});
}
},
{
text: 'Cancel',
textTrusted: false,
addClass: '',
click: (notice) => {
notice.close();
notice.fire('pnotify:cancel', {notice});
}
}
]
- The buttons to display, and their callbacks. If a button has promptTrigger set to true, it will be triggered when the user hits enter in a prompt (unless they hold shift).
}
Because the default buttons fire notice events on confirmation and cancellation, you can listen for them like this:
import { alert } from 'PNotify/dist/es/PNotify.js';
const notice = alert({
title: 'Confirmation Needed',
text: 'Are you sure?',
hide: false,
modules: {
Confirm: {
confirm: true
}
}
});
notice.on('pnotify:confirm', () => {
});
notice.on('pnotify:cancel', () => {
});
Exported Methods and Properties
alert(options)
Create and return a notice with the default type.notice(options)
Create and return a notice with 'notice' type.info(options)
Create and return a notice with 'info' type.success(options)
Create and return a notice with 'success' type.error(options)
Create and return a notice with 'error' type.defaults
Defaults for options.defaultStack
The default stack object.styles
Styles objects.icons
Icons objects.
Instance Methods and Properties
notice.open()
Open the notice.notice.close()
Close the notice.notice.update(options)
Update the notice with new options.notice.on(eventName, callback)
Invokes the callback whenever the notice dispatches the event. Callback receives an event
argument with a detail
prop. Returns a function that removes the handler when invoked.notice.fire(eventName, detail)
Fire an event.notice.getState()
Returns the state of the notice. Can be 'waiting', 'opening', 'open', 'closing', or 'closed'.notice.addModuleClass(element, ...classNames)
This is for modules to add classes to the notice or container element.notice.removeModuleClass(element, ...classNames)
This is for modules to remove classes from the notice or container element.notice.hasModuleClass(element, ...classNames)
This is for modules to test classes on the notice or container element.notice.refs.elem
The notice's DOM element.notice.refs.container
The container DOM element.notice.refs.content
The content DOM element. (Title and text containers are in here.)notice.refs.titleContainer
The title container DOM element.notice.refs.textContainer
The text container DOM element.notice.refs.iconContainer
The icon container DOM element.
Events
Event objects have a detail
property that contains information about the event, including a reference to the notice itself.
pnotify:init
- Fired upon initialization of a new notice. This event bubbles.pnotify:mount
- Fired when the notice has been mounted into the DOM. This event bubbles.pnotify:update
- Fired when the notice's state changes. Careful, this includes internal state and can be very noisy.pnotify:beforeOpen
- Fired before the notice opens. Use preventDefault()
on the event to cancel this action.pnotify:afterOpen
- Fired after the notice opens.pnotify:enterModal
- Fired when the notice enters a modal state. (Opens in a modal stack, or a modalish stack that is in modal state.)pnotify:leaveModal
- Fired when the notice leaves a modal state.pnotify:beforeClose
- Fired before the notice closes. Use preventDefault()
on the event to cancel this action.pnotify:afterClose
- Fired after the notice closes.pnotify:beforeDestroy
- Fired before the notice is destroyed. Use preventDefault()
on the event to cancel this action.pnotify:afterDestroy
- Fired after the notice is destroyed.
From the Svelte Component API.
Don't use these. I'm putting them in here to document that you should not use them. That way, if you do, and you file a bug report, I can point to this section in the README, and tell you that you did a bad.
notice.$set(options)
You should use update(options)
instead. The Svelte API may change.notice.$on(event, callback)
You should use on(event, callback)
instead. The Svelte API may change.notice.$destroy()
You should use close()
with destroy: true
instead. It will animate the notice out and remove it from the stack.notices
array. Removes the component from the DOM and any observers/event listeners.
Stacks
A stack is an instance of the Stack
class used to determine where to position notices and how they interact with each other.
import {alert, Stack} from 'pnotify/dist/PNotify.js';
const myStack = new Stack({
dir1: 'up'
});
alert({
text: 'I\'m a notice centered at the bottom!',
stack: myStack
});
Stack options and their defaults:
dir1: null
The primary stacking direction. Can be 'up'
, 'down'
, 'right'
, or 'left'
.firstpos1: null
Number of pixels from the edge of the context, relative to dir1
, the first notice will appear. If null, the current position of the notice, whatever that is, will be used.spacing1: 25
Number of pixels between notices along dir1
.dir2: null
The secondary stacking direction. Should be a perpendicular direction to dir1
. The notices will continue in this direction when they reach the edge of the viewport along dir1
.firstpos2: null
Number of pixels from the edge of the context, relative to dir2
, the first notice will appear. If null, the current position of the notice, whatever that is, will be used.spacing2: 25
Number of pixels between notices along dir2
.push: 'bottom'
Where, in the stack, to push new notices. Can be 'top'
or 'bottom'
.maxOpen: 1
How many notices are allowed to be open in this stack at once.maxStrategy: 'wait'
The strategy to use to ensure maxOpen
. Can be 'wait'
, which will cause new notices to wait their turn, or 'close'
, which will remove the oldest notice to make room for a new one.maxClosureCausesWait: true
Whether the notices that are closed to abide by maxOpen
when maxStrategy === 'close'
should wait and reopen in turn.modal: 'ish'
Whether the stack should be modal (true
), modeless (false
), or modalish ('ish'
). Modalish stacks are cool. See https://sciactive.com/2020/02/11/the-modalish-notification-flow/.modalishFlash: true
Whether new notices that start waiting in a modalish stack should flash under the leader notice to show that they have been added.overlayClose: true
Whether clicking on the modal overlay should close the stack's notices.overlayClosesPinned: false
Whether clicking on the modal to close notices also closes notices that have been pinned (hide === false
).context: document.body
The DOM element this stack's notices should appear in.
Stack behavior:
- If there is no
dir1
property, the notice will be centered in the context. - If there is a
dir1
and no dir2
, the notices will be centered along the axis of dir1
. - The
firstpos*
values are relative to an edge determined by the corresponding dir*
value.
dirX === 'up'
means firstposX
is relative to the bottom edge.dirX === 'down'
means firstposX
is relative to the top edge.dirX === 'left'
means firstposX
is relative to the right edge.dirX === 'right'
means firstposX
is relative to the left edge.
- Stacks are independent of each other, so a stack doesn't know and doesn't care if it overlaps (and blocks) another stack.
- Stack objects are used and manipulated by PNotify, and therefore, should likely be a variable when passed. Only use
stack: new Stack({...})
in your options if you intend to have only one notice open like that.
Stack methods:
forEach(callback, { start = 'oldest', dir = 'newer', skipModuleHandled = false } = {})
Run a callback for all the notices in the stack. start
can be 'head', 'tail', 'oldest', or 'newest'. dir
can be 'next', 'prev', 'older', or 'newer'.position()
Position all the notices in the stack.queuePosition(milliseconds = 10)
Queue a position call in that many milliseconds, unless another one is queued beforehand.close()
Close all the notices in the stack.open()
Open all the notices in the stack.openLast()
Open the last closed/closing notice in the stack.
There are other methods on the stack class, but you shouldn't use them. They're meant to be internal, so they begin with an underscore.
Stack properties:
stack.notices
- An "array" of notices. It's actually built on the fly from the double linked list the notices are actually stored in.stack.length
- How many notices there are in the stack.stack.leader
- When a stack is modalish, this is the notice that is open in the non-modal state.
All of the options are properties as well.
:warning: Calling something like alert({text: 'notice', stack: new Stack({dir1: 'down', firstpos1: 25})});
may not do what you want. It will create a notice, but that notice will be in its own stack and will overlap other notices.
Example Stack
Here is an example stack with comments to explain. You can play with it here.
const stackBottomModal = new Stack({
dir1: 'up',
firstpos1: 25,
push: 'top',
modal: true,
overlayClose: true,
context: document.getElementById('page-container')
});
If you just want to position a single notice programmatically, and don't want to add any other notices into the stack, you can use something like this:
alert({
text: "Notice that's positioned in its own stack.",
stack: new Stack({
dir1: 'down', dir2: 'right',
firstpos1: 90, firstpos2: 90
})
});
Features
- Rich graphical features and effects.
- Automatic dark mode support.
- Material, Bootstrap 3/4, Font Awesome 4/5, or the stand-alone theme, Bright Theme.
- Mobile styling and swipe support.
- Timed hiding.
- Slick animations with Animate.css.
- Attention getters with Animate.css.
- Highly customizable UI.
- Modalish, modal, and modeless notification flows.
- Sticky notices.
- Optional close and stick buttons.
- Supports non-blocking notices for less intrusive use.
- Notification types: notice, info, success, and error.
- Stacks allow notices to position together or independently.
- Control stack direction and push to top or bottom.
- Confirm dialogs, alert buttons, and prompts.
- RTL language support.
- Feature rich API.
- Desktop notifications based on the Web Notifications standard.
- Dynamically update existing notices.
- Put text, HTML, or DOM elements in notices.
- By default, escapes text to prevent XSS attacks.
- Optional notice history for reshowing old notices.
- Universally compatible.
- Works with any frontend library (React, Angular, Svelte, Vue, Ember, etc.).
- Works well with bundlers (Webpack, Rollup, etc.).
- No dependencies for most features.
Licensing and Additional Info
Copyright 2009-2020 Hunter Perrin
Copyright 2015 Google, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
See http://sciactive.com/pnotify/ for more information, and demos.