Skip to main content

no-alert

JavaScript’s alert, confirm, and prompt functions are obtrusive UI elements and should be replaced with custom UI. They’re also often leftover debugging code.
Rule Type: Suggestion
Fixable: No

Why This Rule Exists

  • Debugging remnants: alert() is often used during debugging and should be removed
  • Poor UX: Browser dialogs are intrusive and block the entire page
  • Limited customization: Can’t match your app’s design
  • Not testable: Hard to test in automated tests

Rule Details

This rule warns about alert, prompt, and confirm function calls that aren’t shadowed by local variables.

Examples

Incorrect Code

alert("here!");

confirm("Are you sure?");

prompt("What's your name?", "John Doe");

Correct Code

// Custom implementations
customAlert("Something happened!");

customConfirm("Are you sure?");

customPrompt("Who are you?");

// Shadowed by local variable
function foo() {
    const alert = myCustomLib.customAlert;
    alert(); // OK - not the global alert
}

// Use console for debugging
console.log("Debug information");
console.warn("Warning message");

Modern Alternatives

Custom Modal Libraries

Use a modal library that matches your app’s design and is non-blocking.
// Instead of alert
import { toast } from 'your-toast-library';
toast.info('Operation completed');

// Instead of confirm  
import { modal } from 'your-modal-library';
const confirmed = await modal.confirm({
  title: 'Are you sure?',
  message: 'This action cannot be undone'
});

// Instead of prompt
const name = await modal.prompt({
  title: 'Enter your name',
  defaultValue: 'John Doe'
});

React Example

// Wrong
function deleteUser() {
  if (confirm('Delete this user?')) {
    api.deleteUser(userId);
  }
}

// Right - Custom modal
function deleteUser() {
  showModal({
    title: 'Confirm Delete',
    message: 'Are you sure you want to delete this user?',
    onConfirm: () => api.deleteUser(userId),
    onCancel: () => {}
  });
}

Toast Notifications

// Instead of alert for notifications
alert('Changes saved');

// Use toast notifications
toast.success('Changes saved successfully', {
  duration: 3000,
  position: 'top-right'
});

Debugging Alternatives

Console Methods

// Instead of alert for debugging
alert(JSON.stringify(user));

// Use console methods
console.log('User:', user);
console.table(users);
console.dir(element);
console.trace();

Debugger Statement

// Instead of alert to pause execution
alert('Check value: ' + x);

// Use debugger
debugger; // Pauses execution in dev tools
console.log('Value:', x);

Logger Library

import logger from 'your-logger';

// Structured logging
logger.debug('User action', { userId, action: 'click' });
logger.info('Request completed', { duration: 150 });
logger.error('Request failed', { error, userId });

Common Patterns

Quick User Feedback

// Wrong
function saveData() {
  api.save(data);
  alert('Saved!');
}

// Right - Toast notification
function saveData() {
  api.save(data);
  toast.success('Saved successfully!');
}

Confirmation Dialogs

// Wrong
function deleteItem(id) {
  if (confirm('Delete this item?')) {
    api.delete(id);
  }
}

// Right - Custom modal
async function deleteItem(id) {
  const confirmed = await confirmDialog({
    title: 'Delete Item',
    message: 'This action cannot be undone',
    confirmText: 'Delete',
    cancelText: 'Cancel'
  });
  
  if (confirmed) {
    await api.delete(id);
    toast.success('Item deleted');
  }
}

User Input

// Wrong
function renameItem(id) {
  const newName = prompt('Enter new name:');
  if (newName) {
    api.rename(id, newName);
  }
}

// Right - Modal with form
async function renameItem(id) {
  const newName = await promptDialog({
    title: 'Rename Item',
    label: 'New name',
    placeholder: 'Enter new name',
    validate: (value) => value.length > 0
  });
  
  if (newName) {
    await api.rename(id, newName);
    toast.success('Item renamed');
  }
}

Testing Benefits

Browser alert dialogs are difficult to test in automated tests.
// Hard to test
function processOrder() {
  try {
    placeOrder();
    alert('Order placed!');
  } catch (e) {
    alert('Order failed');
  }
}

// Easy to test
function processOrder(notifier = toast) {
  try {
    placeOrder();
    notifier.success('Order placed!');
  } catch (e) {
    notifier.error('Order failed');
  }
}

// Test
test('shows success message', () => {
  const mockNotifier = { success: jest.fn() };
  processOrder(mockNotifier);
  expect(mockNotifier.success).toHaveBeenCalled();
});

When Not to Use It

Disable this rule if:
  • You’re writing quick prototypes or demos
  • You’re in a legacy codebase that can’t be updated
  • You’re specifically building debugging tools
For production code, this rule should be enabled.

Configuration

{
  "rules": {
    "no-alert": "error"
  }
}

// Warning instead of error
{
  "rules": {
    "no-alert": "warn"
  }
}