DEV Community

James Parker
James Parker

Posted on

Using React Components in SweetAlert2 with sweetalert2-react-content

sweetalert2-react-content is a library that allows you to use React components as content inside SweetAlert2 modals. This enables you to leverage the full power of React components, hooks, and state management within your alert dialogs, making them more interactive and dynamic. This guide walks through setting up and using React components in SweetAlert2 dialogs with sweetalert2-react-content. This is part 31 of a series on using sweetalert2-react-content with React.

Prerequisites

Before you begin, make sure you have:

  • Node.js version 14.0 or higher installed
  • npm, yarn, or pnpm package manager
  • A React project (version 16.8 or higher) or create-react-app setup
  • Basic knowledge of React components and hooks (useState)
  • Familiarity with SweetAlert2
  • Understanding of JavaScript/TypeScript

Installation

Install sweetalert2-react-content and its dependencies:

npm install sweetalert2 sweetalert2-react-content react react-dom
Enter fullscreen mode Exit fullscreen mode

Or with yarn:

yarn add sweetalert2 sweetalert2-react-content react react-dom
Enter fullscreen mode Exit fullscreen mode

Or with pnpm:

pnpm add sweetalert2 sweetalert2-react-content react react-dom
Enter fullscreen mode Exit fullscreen mode

After installation, your package.json should include:

{
  "dependencies": {
    "sweetalert2": "^11.0.0",
    "sweetalert2-react-content": "^5.0.0",
    "react": "^18.0.0",
    "react-dom": "^18.0.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

Project Setup

Import SweetAlert2 styles and set up the React content wrapper. Update your main entry file:

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import 'sweetalert2/dist/sweetalert2.min.css';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
Enter fullscreen mode Exit fullscreen mode

First Example / Basic Usage

Let's create a simple React component and use it in a SweetAlert2 dialog. First, create a simple component:

// src/SimpleReactContent.jsx
import React from 'react';

function SimpleReactContent() {
  return (
    <div style={{ padding: '20px', textAlign: 'center' }}>
      <h3>Hello from React!</h3>
      <p>This content is rendered using a React component inside SweetAlert2.</p>
    </div>
  );
}

export default SimpleReactContent;
Enter fullscreen mode Exit fullscreen mode

Now, create a component that opens the alert with React content:

// src/App.jsx
import React from 'react';
import Swal from 'sweetalert2';
import withReactContent from 'sweetalert2-react-content';
import SimpleReactContent from './SimpleReactContent';
import './App.css';

const MySwal = withReactContent(Swal);

function App() {
  const showReactAlert = () => {
    MySwal.fire({
      title: 'React Content Alert',
      html: <SimpleReactContent />,
      showConfirmButton: true,
      confirmButtonText: 'OK'
    });
  };

  return (
    <div className="App" style={{ padding: '20px' }}>
      <h1>SweetAlert2 with React Content</h1>
      <button
        onClick={showReactAlert}
        style={{
          padding: '10px 20px',
          backgroundColor: '#007bff',
          color: 'white',
          border: 'none',
          borderRadius: '4px',
          cursor: 'pointer'
        }}
      >
        Show React Alert
      </button>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

This creates a basic alert that displays React component content inside a SweetAlert2 modal.

Understanding the Basics

sweetalert2-react-content works by:

  • withReactContent: Wraps SweetAlert2 to enable React component rendering
  • React Components: You can pass React components directly to the html property
  • State Management: React components can use hooks and manage their own state
  • Event Handling: Components can handle events and interact with the parent

Key concepts:

  • Wrapper Function: withReactContent(Swal) creates a new Swal instance that supports React
  • Component as HTML: Pass React components to the html property instead of strings
  • State Isolation: Each alert instance has its own React component instance
  • Lifecycle: Components mount when the alert opens and unmount when it closes

Here's an example with interactive React content:

// src/InteractiveContent.jsx
import React, { useState } from 'react';

function InteractiveContent() {
  const [count, setCount] = useState(0);

  return (
    <div style={{ padding: '20px', textAlign: 'center' }}>
      <h3>Interactive Counter</h3>
      <p>Count: {count}</p>
      <div style={{ display: 'flex', gap: '10px', justifyContent: 'center' }}>
        <button
          onClick={() => setCount(count - 1)}
          style={{
            padding: '8px 16px',
            backgroundColor: '#dc3545',
            color: 'white',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          Decrease
        </button>
        <button
          onClick={() => setCount(count + 1)}
          style={{
            padding: '8px 16px',
            backgroundColor: '#28a745',
            color: 'white',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          Increase
        </button>
      </div>
    </div>
  );
}

export default InteractiveContent;
Enter fullscreen mode Exit fullscreen mode

Update App.jsx to use the interactive component:

// src/App.jsx
import React from 'react';
import Swal from 'sweetalert2';
import withReactContent from 'sweetalert2-react-content';
import SimpleReactContent from './SimpleReactContent';
import InteractiveContent from './InteractiveContent';
import './App.css';

const MySwal = withReactContent(Swal);

function App() {
  const showReactAlert = () => {
    MySwal.fire({
      title: 'React Content Alert',
      html: <SimpleReactContent />,
      showConfirmButton: true,
      confirmButtonText: 'OK'
    });
  };

  const showInteractiveAlert = () => {
    MySwal.fire({
      title: 'Interactive React Content',
      html: <InteractiveContent />,
      showConfirmButton: true,
      confirmButtonText: 'Close',
      width: '500px'
    });
  };

  return (
    <div className="App" style={{ padding: '20px' }}>
      <h1>SweetAlert2 with React Content</h1>
      <div style={{ display: 'flex', gap: '10px' }}>
        <button
          onClick={showReactAlert}
          style={{
            padding: '10px 20px',
            backgroundColor: '#007bff',
            color: 'white',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          Show Simple Alert
        </button>
        <button
          onClick={showInteractiveAlert}
          style={{
            padding: '10px 20px',
            backgroundColor: '#28a745',
            color: 'white',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          Show Interactive Alert
        </button>
      </div>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Practical Example / Building Something Real

Let's build a contact form component that can be used inside a SweetAlert2 modal:

// src/ContactForm.jsx
import React, { useState } from 'react';

function ContactForm({ onClose }) {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    message: ''
  });
  const [errors, setErrors] = useState({});

  const handleInputChange = (e) => {
    const { name, value } = e.target;
    setFormData(prev => ({ ...prev, [name]: value }));
    if (errors[name]) {
      setErrors(prev => ({ ...prev, [name]: '' }));
    }
  };

  const validateForm = () => {
    const newErrors = {};
    if (!formData.name.trim()) {
      newErrors.name = 'Name is required';
    }
    if (!formData.email.trim()) {
      newErrors.email = 'Email is required';
    } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(formData.email)) {
      newErrors.email = 'Invalid email format';
    }
    if (!formData.message.trim()) {
      newErrors.message = 'Message is required';
    }
    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    if (validateForm()) {
      console.log('Form submitted:', formData);
      alert('Message sent successfully!');
      onClose();
    }
  };

  return (
    <form onSubmit={handleSubmit} style={{ padding: '20px', minWidth: '400px' }}>
      <div style={{ marginBottom: '16px' }}>
        <label
          htmlFor="name"
          style={{
            display: 'block',
            marginBottom: '4px',
            fontWeight: '500'
          }}
        >
          Name *
        </label>
        <input
          type="text"
          id="name"
          name="name"
          value={formData.name}
          onChange={handleInputChange}
          style={{
            width: '100%',
            padding: '8px',
            border: `1px solid ${errors.name ? '#dc3545' : '#ddd'}`,
            borderRadius: '4px',
            fontSize: '14px',
            boxSizing: 'border-box'
          }}
        />
        {errors.name && (
          <div
            style={{
              color: '#dc3545',
              fontSize: '12px',
              marginTop: '4px'
            }}
          >
            {errors.name}
          </div>
        )}
      </div>

      <div style={{ marginBottom: '16px' }}>
        <label
          htmlFor="email"
          style={{
            display: 'block',
            marginBottom: '4px',
            fontWeight: '500'
          }}
        >
          Email *
        </label>
        <input
          type="email"
          id="email"
          name="email"
          value={formData.email}
          onChange={handleInputChange}
          style={{
            width: '100%',
            padding: '8px',
            border: `1px solid ${errors.email ? '#dc3545' : '#ddd'}`,
            borderRadius: '4px',
            fontSize: '14px',
            boxSizing: 'border-box'
          }}
        />
        {errors.email && (
          <div
            style={{
              color: '#dc3545',
              fontSize: '12px',
              marginTop: '4px'
            }}
          >
            {errors.email}
          </div>
        )}
      </div>

      <div style={{ marginBottom: '16px' }}>
        <label
          htmlFor="message"
          style={{
            display: 'block',
            marginBottom: '4px',
            fontWeight: '500'
          }}
        >
          Message *
        </label>
        <textarea
          id="message"
          name="message"
          value={formData.message}
          onChange={handleInputChange}
          rows={4}
          style={{
            width: '100%',
            padding: '8px',
            border: `1px solid ${errors.message ? '#dc3545' : '#ddd'}`,
            borderRadius: '4px',
            fontSize: '14px',
            resize: 'vertical',
            fontFamily: 'inherit',
            boxSizing: 'border-box'
          }}
        />
        {errors.message && (
          <div
            style={{
              color: '#dc3545',
              fontSize: '12px',
              marginTop: '4px'
            }}
          >
            {errors.message}
          </div>
        )}
      </div>

      <div style={{ display: 'flex', gap: '10px', justifyContent: 'flex-end' }}>
        <button
          type="button"
          onClick={onClose}
          style={{
            padding: '8px 16px',
            border: '1px solid #ddd',
            backgroundColor: 'white',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          Cancel
        </button>
        <button
          type="submit"
          style={{
            padding: '8px 16px',
            backgroundColor: '#007bff',
            color: 'white',
            border: 'none',
            borderRadius: '4px',
            cursor: 'pointer'
          }}
        >
          Send Message
        </button>
      </div>
    </form>
  );
}

export default ContactForm;
Enter fullscreen mode Exit fullscreen mode

Now update App.jsx to use the contact form:

// src/App.jsx
import React from 'react';
import Swal from 'sweetalert2';
import withReactContent from 'sweetalert2-react-content';
import ContactForm from './ContactForm';
import './App.css';

const MySwal = withReactContent(Swal);

function App() {
  const showContactForm = () => {
    MySwal.fire({
      title: 'Contact Us',
      html: <ContactForm onClose={() => MySwal.close()} />,
      showConfirmButton: false,
      showCancelButton: false,
      width: '500px',
      allowOutsideClick: true,
      allowEscapeKey: true
    });
  };

  return (
    <div className="App" style={{ padding: '20px' }}>
      <h1>SweetAlert2 with React Content</h1>
      <button
        onClick={showContactForm}
        style={{
          padding: '10px 20px',
          backgroundColor: '#007bff',
          color: 'white',
          border: 'none',
          borderRadius: '4px',
          cursor: 'pointer',
          fontSize: '16px'
        }}
      >
        Open Contact Form
      </button>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

This example demonstrates:

  • Form handling with validation
  • Error display and styling
  • React state management inside alerts
  • Event handling and callbacks
  • Custom styling with inline styles
  • Integration with SweetAlert2 close functionality

Common Issues / Troubleshooting

  1. React component not rendering: Make sure you're using withReactContent(Swal) to create the Swal instance. Regular Swal.fire() doesn't support React components.

  2. State not updating: React components in alerts have isolated state. Each alert instance creates a new component instance. If you need shared state, use React Context or external state management.

  3. Event handlers not working: Ensure event handlers are properly defined in your React components. SweetAlert2 doesn't interfere with React event handling.

  4. Styling issues: Use inline styles or CSS classes in your React components. SweetAlert2's default styles may need to be overridden for custom components.

  5. Component not closing: Pass a close function to your component (like onClose={() => MySwal.close()}) to allow programmatic closing from within the component.

  6. Multiple alerts: Each alert creates a new React component instance. If you need to share data between alerts, use external state management or pass data through props.

Next Steps

Now that you have a basic understanding of sweetalert2-react-content:

  • Learn about passing props to React components in alerts
  • Explore advanced state management patterns
  • Implement custom animations and transitions
  • Add accessibility enhancements
  • Learn about other React alert libraries
  • Check the official repository: https://github.com/sweetalert2/sweetalert2-react-content
  • Look for part 32 of this series for more advanced topics

Summary

You've successfully set up sweetalert2-react-content in your React application and created interactive React components that work inside SweetAlert2 modals. This library enables you to leverage React's component model and state management within alert dialogs.

SEO Keywords

sweetalert2-react-content
React components in alerts
sweetalert2-react-content tutorial
React alert dialogs
sweetalert2-react-content installation
React modal components
sweetalert2-react-content example
React interactive alerts
sweetalert2-react-content setup
React form modals
sweetalert2-react-content hooks
React alert forms
sweetalert2-react-content state
React modal library
sweetalert2-react-content getting started

Top comments (0)