A beautiful, responsive, customizable and accessible replacement for JavaScript's popup boxes
—
Methods for checking popup state, controlling visibility, managing loading states, and updating popup content dynamically.
Methods to check if a popup is currently visible and control popup visibility.
/**
* Determines if a popup is currently shown
* @returns True if a popup is visible, false otherwise
*/
function isVisible(): boolean;
/**
* Closes the currently open SweetAlert2 popup programmatically
* @param result - Optional result object to resolve the popup promise with
*/
function close(result?: Partial<SweetAlertResult>): void;Usage Examples:
// Check if popup is visible before opening another
if (!Swal.isVisible()) {
Swal.fire('No popup is currently open');
} else {
console.log('A popup is already visible');
}
// Close with custom result
Swal.close({
isConfirmed: false,
isDismissed: true,
dismiss: Swal.DismissReason.backdrop
});
// Auto-close after condition
setTimeout(() => {
if (Swal.isVisible()) {
Swal.close();
}
}, 5000);Methods to manage loading states and spinner display.
/**
* Determines if popup is in the loading state
* @returns True if loading spinner is shown, false otherwise
*/
function isLoading(): boolean;
/**
* Shows loader (spinner), useful with AJAX requests
* @param buttonToReplace - Optional button element to replace with loader
*/
function showLoading(buttonToReplace?: HTMLButtonElement | null): void;
/**
* Hides loader and shows back the button which was hidden by showLoading()
*/
function hideLoading(): void;Usage Examples:
// Show loading on confirm button
Swal.fire({
title: 'Processing...',
text: 'Please wait',
allowOutsideClick: false,
didOpen: () => {
Swal.showLoading();
}
});
// Custom loading with specific button
const result = await Swal.fire({
title: 'Upload File',
text: 'Select a file to upload',
showCancelButton: true,
confirmButtonText: 'Upload',
preConfirm: async () => {
Swal.showLoading(Swal.getConfirmButton());
try {
// Simulate upload
await new Promise(resolve => setTimeout(resolve, 2000));
return 'Upload successful';
} catch (error) {
Swal.showValidationMessage('Upload failed');
return false;
} finally {
Swal.hideLoading();
}
}
});
// Check loading state
if (Swal.isLoading()) {
console.log('Currently loading...');
}Methods to update popup content and options while the popup is displayed.
/**
* Updates popup options dynamically
* @param options - Object containing updatable options
*/
function update(options: Pick<SweetAlertOptions, SweetAlertUpdatableParameters>): void;Usage Examples:
// Progress indicator with updates
Swal.fire({
title: 'Processing...',
html: 'Progress: 0%',
allowOutsideClick: false,
didOpen: () => {
let progress = 0;
const interval = setInterval(() => {
progress += 10;
Swal.update({
html: `Progress: ${progress}%`,
title: progress < 100 ? 'Processing...' : 'Complete!'
});
if (progress >= 100) {
clearInterval(interval);
Swal.update({
icon: 'success',
confirmButtonText: 'Done'
});
}
}, 500);
}
});
// Dynamic content based on user interaction
Swal.fire({
title: 'Choose an option',
input: 'select',
inputOptions: {
'option1': 'Option 1',
'option2': 'Option 2',
'option3': 'Option 3'
},
inputPlaceholder: 'Select an option',
showCancelButton: true,
didOpen: () => {
const input = Swal.getInput();
if (input) {
input.addEventListener('change', (e) => {
const value = e.target.value;
let newText = '';
switch(value) {
case 'option1':
newText = 'You selected Option 1 - This is great for beginners';
break;
case 'option2':
newText = 'You selected Option 2 - Perfect for intermediate users';
break;
case 'option3':
newText = 'You selected Option 3 - Advanced users love this';
break;
}
Swal.update({
text: newText
});
});
}
}
});Methods to enable and disable buttons dynamically.
/**
* Enables "Confirm" and "Cancel" buttons
*/
function enableButtons(): void;
/**
* Disables "Confirm" and "Cancel" buttons
*/
function disableButtons(): void;Usage Examples:
// Conditional button enabling
Swal.fire({
title: 'Terms and Conditions',
html: `
<div style="max-height: 200px; overflow-y: auto; text-align: left;">
<p>Please read these terms and conditions carefully...</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit...</p>
</div>
<label style="margin-top: 15px;">
<input type="checkbox" id="agree-checkbox"> I agree to the terms and conditions
</label>
`,
showCancelButton: true,
confirmButtonText: 'Accept',
didOpen: () => {
Swal.disableButtons();
const checkbox = document.getElementById('agree-checkbox');
if (checkbox) {
checkbox.addEventListener('change', (e) => {
if (e.target.checked) {
Swal.enableButtons();
} else {
Swal.disableButtons();
}
});
}
}
});
// Async validation with button control
Swal.fire({
title: 'Enter username',
input: 'text',
inputPlaceholder: 'Username',
showCancelButton: true,
didOpen: () => {
const input = Swal.getInput();
if (input) {
input.addEventListener('input', async (e) => {
const value = e.target.value;
if (value.length < 3) {
Swal.disableButtons();
return;
}
// Simulate username availability check
Swal.disableButtons();
try {
await new Promise(resolve => setTimeout(resolve, 500));
// Assume username is available
Swal.enableButtons();
} catch (error) {
Swal.disableButtons();
}
});
}
}
});The following parameters can be updated using the update() method:
type SweetAlertUpdatableParameters =
| 'allowEscapeKey'
| 'allowOutsideClick'
| 'background'
| 'buttonsStyling'
| 'cancelButtonAriaLabel'
| 'cancelButtonColor'
| 'cancelButtonText'
| 'closeButtonAriaLabel'
| 'closeButtonHtml'
| 'confirmButtonAriaLabel'
| 'confirmButtonColor'
| 'confirmButtonText'
| 'currentProgressStep'
| 'customClass'
| 'denyButtonAriaLabel'
| 'denyButtonColor'
| 'denyButtonText'
| 'didClose'
| 'didDestroy'
| 'footer'
| 'hideClass'
| 'html'
| 'icon'
| 'iconColor'
| 'imageAlt'
| 'imageHeight'
| 'imageUrl'
| 'imageWidth'
| 'preConfirm'
| 'preDeny'
| 'progressSteps'
| 'reverseButtons'
| 'showCancelButton'
| 'showCloseButton'
| 'showConfirmButton'
| 'showDenyButton'
| 'text'
| 'title'
| 'titleText'
| 'theme'
| 'willClose';// Multi-step wizard with state management
let currentStep = 1;
const totalSteps = 3;
const showStep = (step: number) => {
const stepData = {
1: {
title: 'Step 1: Personal Information',
html: '<input id="name" class="swal2-input" placeholder="Your name">',
confirmButtonText: 'Next'
},
2: {
title: 'Step 2: Contact Details',
html: '<input id="email" class="swal2-input" placeholder="Your email">',
confirmButtonText: 'Next',
showCancelButton: true
},
3: {
title: 'Step 3: Confirmation',
html: 'Please review your information before submitting.',
confirmButtonText: 'Submit',
showCancelButton: true
}
};
Swal.update({
...stepData[step],
progressSteps: ['1', '2', '3'],
currentProgressStep: step - 1
});
};
// Real-time validation with state updates
Swal.fire({
title: 'Form Validation Example',
html: `
<input id="username" class="swal2-input" placeholder="Username (min 3 chars)">
<input id="password" class="swal2-input" type="password" placeholder="Password (min 6 chars)">
<input id="confirm" class="swal2-input" type="password" placeholder="Confirm password">
`,
showCancelButton: true,
confirmButtonText: 'Register',
didOpen: () => {
Swal.disableButtons();
const validateForm = () => {
const username = document.getElementById('username').value;
const password = document.getElementById('password').value;
const confirm = document.getElementById('confirm').value;
const isValid = username.length >= 3 &&
password.length >= 6 &&
password === confirm;
if (isValid) {
Swal.enableButtons();
Swal.update({
text: '✓ Form is valid',
icon: undefined
});
} else {
Swal.disableButtons();
let message = 'Please fix the following:';
if (username.length < 3) message += '\n• Username too short';
if (password.length < 6) message += '\n• Password too short';
if (password !== confirm) message += '\n• Passwords do not match';
Swal.update({
text: message,
icon: 'warning'
});
}
};
['username', 'password', 'confirm'].forEach(id => {
document.getElementById(id).addEventListener('input', validateForm);
});
}
});Install with Tessl CLI
npx tessl i tessl/npm-sweetalert2