Introduction
Headless and runtime-dependency-free toast notifications library. The core (wiss) is a pure TypeScript "brain" —state, queue, timers— that knows nothing about the DOM or any framework. The visual layer is interchangeable: by default it brings its own themes (light and dark) or you can choose to inherit the theme from your project via daisyUI or shadcn/ui to adapt to your current design.
Installation
pnpm add wissfortpnpm add wissfortSound & Interactions
wissfort heavily relies on cuelume for its sound system. This incredible library synthesizes audio live without using heavy .mp3 files, keeping the performance impact completely zero (less than 40 KB uncompressed).
Sound is enabled by default, but if you want to disable it globally, you can do so in the configuration:
import { toaster } from 'wissfort';
toaster({ sound: false });import { toaster } from 'wissfort';
toaster({ sound: false });You can also customize the sound that plays when a single notification is fired by passing the sound name in the sound option:
toast.info('Notificación con sonido especial', { sound: 'sparkle' });toast.info('Notificación con sonido especial', { sound: 'sparkle' });Default sounds:
Each toast type comes with a pre-assigned cuelume sound that perfectly fits its intention:
- success:
success - error:
press - warning:
chime - info:
droplet - loading:
bloom
Interactive Sound Catalog
Explore all available sounds by clicking on the buttons below. Each will trigger an info toast but with its respective custom sound.
import { toast } from 'wissfort';
// Prueba cualquier sonido personalizado
toast.info('Chime sonando', { sound: 'chime' });
toast.info('Mensaje discreto', { sound: 'whisper' });
toast.info('Error mecánico', { sound: 'toggle' });import { toast } from 'wissfort';
// Prueba cualquier sonido personalizado
toast.info('Chime sonando', { sound: 'chime' });
toast.info('Mensaje discreto', { sound: 'whisper' });
toast.info('Error mecánico', { sound: 'toggle' });Basic Usage
Import the toast function to trigger different types of notifications.
Simple Notifications
import { toast } from 'wissfort';
toast.success('Usuario creado');
toast.error('Algo salió mal');
toast.warning('Revisa este campo');
toast.info('Nueva actualización disponible');import { toast } from 'wissfort';
toast.success('Usuario creado');
toast.error('Algo salió mal');
toast.warning('Revisa este campo');
toast.info('Nueva actualización disponible');💡 You can edit the code of any example in its "Code" tab and run it live.
Toast with Action
import { toast } from 'wissfort';
toast.show('Elemento eliminado', {
action: {
label: 'Deshacer',
onClick: () => toast.success('Acción deshecha correctamente')
}
});import { toast } from 'wissfort';
toast.show('Elemento eliminado', {
action: {
label: 'Deshacer',
onClick: () => toast.success('Acción deshecha correctamente')
}
});Toast with Promise
import { toast } from 'wissfort';
toast.promise(
fetch('/api/users'),
{
loading: 'Cargando usuarios...',
success: 'Usuarios cargados correctamente',
error: 'Error al cargar usuarios',
}
);import { toast } from 'wissfort';
toast.promise(
fetch('/api/users'),
{
loading: 'Cargando usuarios...',
success: 'Usuarios cargados correctamente',
error: 'Error al cargar usuarios',
}
);Options per Toast
You can pass a configuration object as the second parameter to any method to customize an individual toast.
Toast with Description
import { toast } from 'wissfort';
toast.success('¡Archivo guardado!', {
description: 'El archivo se guardó correctamente en tu carpeta local.'
});import { toast } from 'wissfort';
toast.success('¡Archivo guardado!', {
description: 'El archivo se guardó correctamente en tu carpeta local.'
});Change Icon
import { toast } from 'wissfort';
toast.info('Nueva actualización', {
icon: '🚀' // Puedes pasar un string, HTML o SVG
});import { toast } from 'wissfort';
toast.info('Nueva actualización', {
icon: '🚀' // Puedes pasar un string, HTML o SVG
});Progress Bar
import { toast } from 'wissfort';
toast.info('Descargando archivo...', {
duration: 5000,
progressBar: true
});import { toast } from 'wissfort';
toast.info('Descargando archivo...', {
duration: 5000,
progressBar: true
});History
Wissfort keeps a record of the toasts that have appeared on screen. You can access or clear them using the API.
import { toast } from 'wissfort';
const historial = toast.history();
console.log(historial); // Array con los toasts anteriores
// Para limpiar el historial:
// toast.clearHistory();import { toast } from 'wissfort';
const historial = toast.history();
console.log(historial); // Array con los toasts anteriores
// Para limpiar el historial:
// toast.clearHistory();Global Configuration
The toaster() function accepts an object to configure the global behavior of all toasts.
Dark / Light Mode
import { toaster } from 'wissfort/vanilla';
// Cambia globalmente el tema visual
toaster({ theme: 'neon' }); // 'light' | 'dark' | 'neon' | 'pastel' | 'brutal' | 'pop' | 'shadcn'import { toaster } from 'wissfort/vanilla';
// Cambia globalmente el tema visual
toaster({ theme: 'neon' }); // 'light' | 'dark' | 'neon' | 'pastel' | 'brutal' | 'pop' | 'shadcn'Design Format (Wiss vs Island)
You can change the aesthetics of the notifications between a wiss design or a "dynamic island" type.
import { toaster } from 'wissfort/vanilla';
// wiss: Bordes definidos
// island: Diseño más suave e integrado
toaster({ format: 'island' });import { toaster } from 'wissfort/vanilla';
// wiss: Bordes definidos
// island: Diseño más suave e integrado
toaster({ format: 'island' });Toast Limit
import { toaster } from 'wissfort/vanilla';
// Máximo de toasts visibles al mismo tiempo
toaster({ maxToasts: 2 });import { toaster } from 'wissfort/vanilla';
// Máximo de toasts visibles al mismo tiempo
toaster({ maxToasts: 2 });Behavior (Replace Behavior)
Controls what happens when the limit is reached. normal stacks the notifications, wiss visually replaces the oldest one with an animation.
import { toaster } from 'wissfort/vanilla';
toaster({ replaceBehavior: 'wiss' }); // 'normal' | 'wiss'import { toaster } from 'wissfort/vanilla';
toaster({ replaceBehavior: 'wiss' }); // 'normal' | 'wiss'Usage in Astro
---
// Layout.astro
---
<slot />
<script>
import { toaster } from 'wissfort/vanilla';
toaster();
</script>---
// Layout.astro
---
<slot />
<script>
import { toaster } from 'wissfort/vanilla';
toaster();
</script>Then, from any component or client script:
import { toast } from 'wissfort';
toast.success('¡Listo!');import { toast } from 'wissfort';
toast.success('¡Listo!');Themes, daisyUI and shadcn/ui
By default, the library uses its own themes (light and dark) built with Tailwind. This ensures the toasts look good out of the box.
Integration with shadcn/ui
If you use shadcn/ui (in Tailwind v4 or using absolute/hex/oklch color variables), wiss now includes native support. Set theme: 'shadcn' and the toasts will automatically map their colors to your project variables (like --background, --foreground, --primary, --destructive, etc.):
import { toaster } from 'wissfort/vanilla';
toaster({
theme: 'shadcn',
position: 'bottom-right',
duration: 4000,
});import { toaster } from 'wissfort/vanilla';
toaster({
theme: 'shadcn',
position: 'bottom-right',
duration: 4000,
});Note: If you are using an older version of shadcn where variables only export the raw HSL values (e.g. 0 0% 100%), you can still use theme: 'light' or 'dark' and map the --wiss-* variables in your globals.css file by wrapping them in the hsl() function.
Integration with daisyUI
If you prefer the toasts to inherit the active daisyUI style (light, dark, cyberpunk, etc.), you can use theme: 'daisy':
import { toaster } from 'wissfort/vanilla';
toaster({
theme: 'daisy', // 'dark' (default) | 'light' | 'shadcn' | 'daisy'
position: 'bottom-right',
duration: 4000,
offset: 16,
});import { toaster } from 'wissfort/vanilla';
toaster({
theme: 'daisy', // 'dark' (default) | 'light' | 'shadcn' | 'daisy'
position: 'bottom-right',
duration: 4000,
offset: 16,
});With theme: 'daisy', wiss injects daisyUI classes (alert, alert-success, alert-error, ...) instead of its own. Thus, the final color is resolved by the daisyUI theme configured in your project.
If you don't need to integrate it with daisyUI or prefer the default wiss styles, simply don't pass the theme property (or use 'light'/'dark') and it will use the default theme.
Tailwind CSS Configuration
The wiss themes come with utility classes built into the library code (node_modules). For styles to apply correctly, you must tell Tailwind to process these files.
For Tailwind CSS v4 (and DaisyUI 5)
In version 4, Tailwind uses CSS-based configuration. Simply add the @source directive in your main CSS file (where you import tailwind) pointing to the library:
/* app.css o globals.css */
@import "tailwindcss";
@source "../node_modules/wiss"; /* Ajusta la ruta si es necesario *//* app.css o globals.css */
@import "tailwindcss";
@source "../node_modules/wiss"; /* Ajusta la ruta si es necesario */For Tailwind CSS v3 (and DaisyUI 4)
If you are still using version 3 of Tailwind, you must add the wiss path to the content array in your configuration file:
// tailwind.config.js
export default {
content: [
'./src/**/*.{astro,html,js,ts,vue,svelte,tsx}',
'./node_modules/wiss/dist/**/*.{js,mjs}',
],
// ...
};// tailwind.config.js
export default {
content: [
'./src/**/*.{astro,html,js,ts,vue,svelte,tsx}',
'./node_modules/wiss/dist/**/*.{js,mjs}',
],
// ...
};Usage in React
import { Toaster } from 'wissfort/react';
import { toast } from 'wissfort';
function App() {
return (
<>
<Toaster position="bottom-right" theme="dark" />
<button onClick={() => toast.success('¡Hecho!')}>Notify</button>
</>
);
}import { Toaster } from 'wissfort/react';
import { toast } from 'wissfort';
function App() {
return (
<>
<Toaster position="bottom-right" theme="dark" />
<button onClick={() => toast.success('¡Hecho!')}>Notify</button>
</>
);
}Usage in Vue
<script setup>
import { Toaster } from 'wissfort/vue';
import { toast } from 'wissfort';
</script>
<template>
<Toaster position="bottom-right" theme="dark" />
<button @click="toast.success('¡Hecho!')">Notify</button>
</template><script setup>
import { Toaster } from 'wissfort/vue';
import { toast } from 'wissfort';
</script>
<template>
<Toaster position="bottom-right" theme="dark" />
<button @click="toast.success('¡Hecho!')">Notify</button>
</template>Usage in Svelte
For Svelte 5:
<script>
import { toaster } from 'wissfort/svelte';
import { toast } from 'wissfort';
$effect(() => toaster({ position: 'bottom-right', theme: 'dark' }));
</script>
<button onclick={() => toast.success('¡Hecho!')}>Notify</button><script>
import { toaster } from 'wissfort/svelte';
import { toast } from 'wissfort';
$effect(() => toaster({ position: 'bottom-right', theme: 'dark' }));
</script>
<button onclick={() => toast.success('¡Hecho!')}>Notify</button>For Svelte 3/4:
<script>
import { onMount } from 'svelte';
import { toaster } from 'wissfort/svelte';
import { toast } from 'wissfort';
onMount(() => toaster({ position: 'bottom-right', theme: 'dark' }));
</script>
<button on:click={() => toast.success('¡Hecho!')}>Notify</button><script>
import { onMount } from 'svelte';
import { toaster } from 'wissfort/svelte';
import { toast } from 'wissfort';
onMount(() => toaster({ position: 'bottom-right', theme: 'dark' }));
</script>
<button on:click={() => toast.success('¡Hecho!')}>Notify</button>Roadmap
Out of scope in this phase, planned for later:
- Website/Docs improvements
- Usage demo for framework adapters.
- Add new formats: customized for users who don't use daisyui or shadcn/ui.
- Add new animations and document them.
- Implement performance improvements.
- Add new icons for notifications.
- Add new sounds for notifications.