Modern Notification Library for Web Apps – FlashyJS

Category: Javascript , Notification | June 24, 2025
AuthorPabloTheBlink
Last UpdateJune 24, 2025
LicenseMIT
Views153 views
Modern Notification Library for Web Apps – FlashyJS

FlashyJS is a lightweight, zero-dependency JavaScript library for creating modern, customizable toast notifications with multiple types, animations, and position options.

Features:

  • Multiple notification types (success, error, warning, info, default)
  • Six positioning options for flexible layout integration
  • Four animation styles (slide, fade, bounce, zoom)
  • Light and dark theme support
  • Responsive design with mobile optimization
  • Progress bar with customizable duration
  • Click and close callback functions
  • Framework-agnostic (ES modules, CommonJS, global script)

How to use it:

1. Install FlashyJS and import it into your project.

# Yarn
$ yarn add @pablotheblink/flashyjs
# NPM
$ npm install @pablotheblink/flashyjs
// ES Modules
import flashy from "@pablotheblink/flashyjs";
// CommonJS
const flashy = require("@pablotheblink/flashyjs");

2. For direct browser usage or quick prototyping:

<script src="/path/to//flashy.min.js"></script>

3. Display toast notifications:

// Display basic notification
flashy("Operation completed successfully");
// Type-specific notifications
flashy.success("Data saved successfully");
flashy.error("Connection failed - please retry");
flashy.warning("Session expires in 5 minutes");
flashy.info("New features available in settings");

4. Configure each notification with an options object:

  • type: string – Sets the notification style. Accepts 'success', 'error', 'warning', 'info', or 'default'.
  • position: string – Defines where the notification appears on the screen. Accepts 'top-left', 'top-center', 'top-right', 'bottom-left', 'bottom-center', or 'bottom-right'.
  • duration: number – The time in milliseconds before the notification automatically closes. A value of 0 makes it permanent until manually closed.
  • closable: boolean – If true, a close button is displayed on the notification.
  • animation: string – The animation used for showing and hiding the notification. Accepts 'slide', 'fade', 'bounce', or 'zoom'.
  • theme: string – The color scheme for the notification. Accepts 'light' or 'dark'.
  • icon: string – A custom icon to display. You can use an emoji or an HTML string.
  • onClick: function – A callback function that executes when a user clicks on the notification.
  • onClose: function – A callback function that executes when the notification is closed, either automatically or by the user.
flashy("Operation completed successfully",{
  type: "default",
  position: "top-right",
  duration: 4000,
  closable: true,
  animation: "slide",
  theme: "light",
  icon: null,
  onClick: null,
  onClose: null,
});

5. Or set global defaults:

flashy.setDefaults({
  type: "default",
  position: "top-right",
  duration: 4000,
  closable: true,
  animation: "slide",
  theme: "light",
  icon: null,
  onClick: null,
  onClose: null,
});

6. More API methods:

// Retrieve current defaults
const currentOptions = flashy.getOptions();
// Close all active notifications
flashy.closeAll();
// Destroy all notifications and cleanup
flashy.destroy();

7. Customize the appearance of the toast notifications by overriding the default CSS styles:

.flashy-container {
  position: fixed;
  z-index: 10000;
  pointer-events: none;
}
.flashy-container.top-left { top: 20px; left: 20px; }
.flashy-container.top-center { top: 20px; left: 50%; transform: translateX(-50%); }
.flashy-container.top-right { top: 20px; right: 20px; }
.flashy-container.bottom-left { bottom: 20px; left: 20px; }
.flashy-container.bottom-center { bottom: 20px; left: 50%; transform: translateX(-50%); }
.flashy-container.bottom-right { bottom: 20px; right: 20px; }
.flashy-notification {
  display: flex;
  align-items: center;
  min-width: 300px;
  max-width: 500px;
  margin: 8px 0;
  padding: 16px 20px;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  font-size: 14px;
  line-height: 1.4;
  pointer-events: auto;
  cursor: pointer;
  border-left: 4px solid;
  position: relative;
  overflow: hidden;
  opacity: 0;
}
.flashy-notification:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);
  transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.flashy-notification.light { background: #ffffff; color: #333333; }
.flashy-notification.dark { background: #2d3748; color: #e2e8f0; }
.flashy-notification.success { border-left-color: #4CAF50; }
.flashy-notification.error { border-left-color: #f44336; }
.flashy-notification.warning { border-left-color: #ff9800; }
.flashy-notification.info { border-left-color: #2196F3; }
.flashy-notification.default { border-left-color: #607d8b; }
.flashy-notification.success.light { background: #f1f8e9; }
.flashy-notification.error.light { background: #ffebee; }
.flashy-notification.warning.light { background: #fff3e0; }
.flashy-notification.info.light { background: #e3f2fd; }
.flashy-icon { font-size: 18px; margin-right: 12px; flex-shrink: 0; }
.flashy-content { flex: 1; word-wrap: break-word; }
.flashy-close {
  background: none;
  border: none;
  font-size: 18px;
  cursor: pointer;
  margin-left: 12px;
  opacity: 0.7;
  transition: opacity 0.2s;
  padding: 0;
  width: 20px;
  height: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: inherit;
}
.flashy-close:hover { opacity: 1; }
.flashy-progress {
  position: absolute;
  bottom: 0;
  left: 0;
  height: 3px;
  background: rgba(0, 0, 0, 0.2);
  transition: width linear;
}
@keyframes flashy-slide-in-right {
  from { transform: translateX(100%); opacity: 0; }
  to { transform: translateX(0); opacity: 1; }
}
@keyframes flashy-slide-in-left {
  from { transform: translateX(-100%); opacity: 0; }
  to { transform: translateX(0); opacity: 1; }
}
@keyframes flashy-slide-in-top {
  from { transform: translateY(-100%); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}
@keyframes flashy-slide-in-bottom {
  from { transform: translateY(100%); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}
@keyframes flashy-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
@keyframes flashy-bounce-in {
  0% { transform: scale(0.3); opacity: 0; }
  50% { transform: scale(1.05); opacity: 0.8; }
  70% { transform: scale(0.9); opacity: 0.9; }
  100% { transform: scale(1); opacity: 1; }
}
@keyframes flashy-zoom-in {
  0% { transform: scale(0); opacity: 0; }
  50% { transform: scale(1.1); opacity: 0.8; }
  100% { transform: scale(1); opacity: 1; }
}
@keyframes flashy-exit {
  from { opacity: 1; }
  to { opacity: 0; }
}
.flashy-notification.animate-slide.top-left { animation: flashy-slide-in-left 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
.flashy-notification.animate-slide.top-center { animation: flashy-slide-in-top 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
.flashy-notification.animate-slide.top-right { animation: flashy-slide-in-right 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
.flashy-notification.animate-slide.bottom-left { animation: flashy-slide-in-left 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
.flashy-notification.animate-slide.bottom-center { animation: flashy-slide-in-bottom 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
.flashy-notification.animate-slide.bottom-right { animation: flashy-slide-in-right 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
.flashy-notification.animate-fade { animation: flashy-fade-in 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
.flashy-notification.animate-bounce { animation: flashy-bounce-in 0.5s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
.flashy-notification.animate-zoom { animation: flashy-zoom-in 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
.flashy-notification.removing { animation: flashy-exit 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
@media (max-width: 768px) {
  .flashy-notification {
    min-width: 280px;
    max-width: calc(100vw - 40px);
    margin: 6px 0;
    padding: 12px 16px;
    font-size: 13px;
  }
  .flashy-container {
    left: 20px !important;
    right: 20px !important;
    transform: none !important;
  }
  .flashy-container.top-center,
  .flashy-container.bottom-center {
    left: 20px !important;
    right: 20px !important;
  }
}

FAQs:

Q: How does closeAll() differ from destroy()?
A: flashy.closeAll() removes all the individual notification elements currently on the screen but leaves the main container in the DOM, ready for new notifications. flashy.destroy() removes everything, including the main container. You’d use destroy() if you’re completely done with notifications on a page, for example, when a component unmounts in a framework like React or Vue.

Q: Can I display multiple notifications simultaneously?
A: Yes, Flashy.js automatically stacks notifications in the chosen position. The library calculates spacing and prevents overlaps, though displaying too many notifications simultaneously can overwhelm users.

Q: How do I handle notifications in single-page applications?
A: Call flashy.destroy() during route changes or component unmounting to prevent memory leaks. I typically set up global error handlers that use Flashy.js and initialize default settings once during application startup.

Q: Does it work with server-side rendering?
A: Flashy.js requires DOM access, so it won’t work during server-side rendering. Initialize it in client-side code after the DOM loads. For Next.js or similar frameworks, use dynamic imports with ssr: false.

Q: How do I prevent notification spam during rapid user actions?
A: Implement debouncing in your application logic before calling Flashy.js, or use the closeAll() method before showing new notifications. You can also check existing notifications using the internal state if you need to prevent duplicates.

You Might Be Interested In:


Leave a Reply