DEV Community

Patrick Moore
Patrick Moore

Posted on

Advanced Reactive Buttons with reactive-button in React

reactive-button is a React button component library that provides reactive states and animations for buttons. It offers loading states, success/error feedback, and smooth transitions to create interactive button experiences. This guide walks through advanced usage of reactive-button with React, including state management, custom animations, and complex button configurations.

Demo animation

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 hooks (useState, useCallback)
  • Familiarity with JavaScript/TypeScript
  • Understanding of async operations

Installation

Install reactive-button using your preferred package manager:

npm install reactive-button
Enter fullscreen mode Exit fullscreen mode

Or with yarn:

yarn add reactive-button
Enter fullscreen mode Exit fullscreen mode

Or with pnpm:

pnpm add reactive-button
Enter fullscreen mode Exit fullscreen mode

After installation, your package.json should include:

{
  "dependencies": {
    "reactive-button": "^0.4.0",
    "react": "^18.0.0",
    "react-dom": "^18.0.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

Project Setup

reactive-button requires minimal setup. Import the component and you're ready to use it.

First Example / Basic Usage

Let's create a simple reactive button. Create a new file src/ReactiveButtonExample.jsx:

// src/ReactiveButtonExample.jsx
import React, { useState } from 'react';
import ReactiveButton from 'reactive-button';

function ReactiveButtonExample() {
  const [buttonState, setButtonState] = useState('idle');

  const handleClick = async () => {
    setButtonState('loading');
    // Simulate async operation
    await new Promise(resolve => setTimeout(resolve, 2000));
    setButtonState('success');
    setTimeout(() => setButtonState('idle'), 2000);
  };

  return (
    <div style={{ padding: '20px', textAlign: 'center' }}>
      <h2>Basic Reactive Button Example</h2>
      <ReactiveButton
        buttonState={buttonState}
        onClick={handleClick}
        color="primary"
        idleText="Click Me"
        loadingText="Loading..."
        successText="Success!"
        errorText="Error"
        shadow={true}
        rounded={true}
        size="medium"
      />
    </div>
  );
}

export default ReactiveButtonExample;
Enter fullscreen mode Exit fullscreen mode

Update your App.jsx:

// src/App.jsx
import React from 'react';
import ReactiveButtonExample from './ReactiveButtonExample';
import './App.css';

function App() {
  return (
    <div className="App">
      <ReactiveButtonExample />
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

This creates a reactive button with loading and success states.

Understanding the Basics

reactive-button provides several key features:

  • Button states: idle, loading, success, error
  • State management: Control button state programmatically
  • Custom text: Different text for each state
  • Animations: Smooth transitions between states
  • Styling: Customizable colors, sizes, and styles
  • Event handling: onClick handler for button actions

Key concepts for advanced usage:

  • State control: Use buttonState prop to control button state
  • State values: 'idle', 'loading', 'success', 'error'
  • Async operations: Handle async operations with state changes
  • Customization: Extensive styling and behavior options
  • Event handling: Use onClick for button actions

Here's an example with error handling:

// src/AdvancedReactiveButtonExample.jsx
import React, { useState } from 'react';
import ReactiveButton from 'reactive-button';

function AdvancedReactiveButtonExample() {
  const [buttonState, setButtonState] = useState('idle');
  const [shouldError, setShouldError] = useState(false);

  const handleClick = async () => {
    setButtonState('loading');
    try {
      await new Promise((resolve, reject) => {
        setTimeout(() => {
          if (shouldError) {
            reject(new Error('Operation failed'));
          } else {
            resolve();
          }
        }, 2000);
      });
      setButtonState('success');
      setTimeout(() => {
        setButtonState('idle');
        setShouldError(false);
      }, 2000);
    } catch (error) {
      setButtonState('error');
      setTimeout(() => {
        setButtonState('idle');
      }, 2000);
    }
  };

  return (
    <div style={{ padding: '20px', textAlign: 'center' }}>
      <h2>Advanced Reactive Button</h2>
      <div style={{ marginBottom: '20px' }}>
        <label>
          <input
            type="checkbox"
            checked={shouldError}
            onChange={(e) => setShouldError(e.target.checked)}
            style={{ marginRight: '5px' }}
          />
          Simulate Error
        </label>
      </div>
      <ReactiveButton
        buttonState={buttonState}
        onClick={handleClick}
        color="primary"
        idleText="Submit"
        loadingText="Processing..."
        successText="Success!"
        errorText="Failed"
        shadow={true}
        rounded={true}
        size="large"
        block={false}
      />
    </div>
  );
}

export default AdvancedReactiveButtonExample;
Enter fullscreen mode Exit fullscreen mode

Practical Example / Building Something Real

Let's build a comprehensive button system with different use cases:

// src/ReactiveButtonSystem.jsx
import React, { useState } from 'react';
import ReactiveButton from 'reactive-button';

function ReactiveButtonSystem() {
  const [submitState, setSubmitState] = useState('idle');
  const [deleteState, setDeleteState] = useState('idle');
  const [downloadState, setDownloadState] = useState('idle');
  const [saveState, setSaveState] = useState('idle');

  const handleSubmit = async () => {
    setSubmitState('loading');
    await new Promise(resolve => setTimeout(resolve, 2000));
    setSubmitState('success');
    setTimeout(() => setSubmitState('idle'), 2000);
  };

  const handleDelete = async () => {
    if (!confirm('Are you sure you want to delete?')) return;
    setDeleteState('loading');
    await new Promise(resolve => setTimeout(resolve, 1500));
    setDeleteState('success');
    setTimeout(() => setDeleteState('idle'), 2000);
  };

  const handleDownload = async () => {
    setDownloadState('loading');
    await new Promise(resolve => setTimeout(resolve, 2500));
    setDownloadState('success');
    setTimeout(() => setDownloadState('idle'), 2000);
  };

  const handleSave = async () => {
    setSaveState('loading');
    await new Promise(resolve => setTimeout(resolve, 1000));
    setSaveState('success');
    setTimeout(() => setSaveState('idle'), 2000);
  };

  return (
    <div style={{ padding: '20px', maxWidth: '600px', margin: '0 auto' }}>
      <h1>Reactive Button System</h1>

      {/* Form Buttons */}
      <section style={{ marginBottom: '40px', padding: '20px', border: '1px solid #ddd', borderRadius: '8px' }}>
        <h2>Form Buttons</h2>
        <div style={{ display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
          <ReactiveButton
            buttonState={submitState}
            onClick={handleSubmit}
            color="primary"
            idleText="Submit"
            loadingText="Submitting..."
            successText="Submitted!"
            shadow={true}
            rounded={true}
          />
          <ReactiveButton
            buttonState={saveState}
            onClick={handleSave}
            color="secondary"
            idleText="Save"
            loadingText="Saving..."
            successText="Saved!"
            shadow={true}
            rounded={true}
          />
        </div>
      </section>

      {/* Action Buttons */}
      <section style={{ marginBottom: '40px', padding: '20px', border: '1px solid #ddd', borderRadius: '8px' }}>
        <h2>Action Buttons</h2>
        <div style={{ display: 'flex', gap: '10px', flexWrap: 'wrap' }}>
          <ReactiveButton
            buttonState={downloadState}
            onClick={handleDownload}
            color="primary"
            idleText="Download"
            loadingText="Downloading..."
            successText="Downloaded!"
            shadow={true}
            rounded={true}
          />
          <ReactiveButton
            buttonState={deleteState}
            onClick={handleDelete}
            color="red"
            idleText="Delete"
            loadingText="Deleting..."
            successText="Deleted!"
            shadow={true}
            rounded={true}
          />
        </div>
      </section>

      {/* Size Variations */}
      <section style={{ marginBottom: '40px', padding: '20px', border: '1px solid #ddd', borderRadius: '8px' }}>
        <h2>Size Variations</h2>
        <div style={{ display: 'flex', gap: '10px', alignItems: 'center', flexWrap: 'wrap' }}>
          <ReactiveButton
            buttonState="idle"
            onClick={() => alert('Small clicked')}
            color="primary"
            idleText="Small"
            size="small"
            shadow={true}
            rounded={true}
          />
          <ReactiveButton
            buttonState="idle"
            onClick={() => alert('Medium clicked')}
            color="primary"
            idleText="Medium"
            size="medium"
            shadow={true}
            rounded={true}
          />
          <ReactiveButton
            buttonState="idle"
            onClick={() => alert('Large clicked')}
            color="primary"
            idleText="Large"
            size="large"
            shadow={true}
            rounded={true}
          />
        </div>
      </section>
    </div>
  );
}

export default ReactiveButtonSystem;
Enter fullscreen mode Exit fullscreen mode

Now create a form with reactive buttons:

// src/FormWithReactiveButtons.jsx
import React, { useState } from 'react';
import ReactiveButton from 'reactive-button';

function FormWithReactiveButtons() {
  const [formData, setFormData] = useState({
    name: '',
    email: ''
  });
  const [submitState, setSubmitState] = useState('idle');
  const [resetState, setResetState] = useState('idle');

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

  const handleSubmit = async () => {
    setSubmitState('loading');
    try {
      // Simulate API call
      await new Promise(resolve => setTimeout(resolve, 2000));
      setSubmitState('success');
      setFormData({ name: '', email: '' });
      setTimeout(() => setSubmitState('idle'), 2000);
    } catch (error) {
      setSubmitState('error');
      setTimeout(() => setSubmitState('idle'), 2000);
    }
  };

  const handleReset = async () => {
    setResetState('loading');
    await new Promise(resolve => setTimeout(resolve, 500));
    setFormData({ name: '', email: '' });
    setResetState('success');
    setTimeout(() => setResetState('idle'), 1000);
  };

  return (
    <div style={{ padding: '20px', maxWidth: '500px', margin: '0 auto' }}>
      <h2>Form with Reactive Buttons</h2>
      <form onSubmit={(e) => { e.preventDefault(); handleSubmit(); }}>
        <div style={{ marginBottom: '16px' }}>
          <label style={{ display: 'block', marginBottom: '4px', fontWeight: '500' }}>
            Name:
          </label>
          <input
            type="text"
            name="name"
            value={formData.name}
            onChange={handleInputChange}
            required
            style={{
              width: '100%',
              padding: '8px',
              border: '1px solid #ddd',
              borderRadius: '4px',
              boxSizing: 'border-box'
            }}
          />
        </div>
        <div style={{ marginBottom: '16px' }}>
          <label style={{ display: 'block', marginBottom: '4px', fontWeight: '500' }}>
            Email:
          </label>
          <input
            type="email"
            name="email"
            value={formData.email}
            onChange={handleInputChange}
            required
            style={{
              width: '100%',
              padding: '8px',
              border: '1px solid #ddd',
              borderRadius: '4px',
              boxSizing: 'border-box'
            }}
          />
        </div>
        <div style={{ display: 'flex', gap: '10px' }}>
          <ReactiveButton
            buttonState={submitState}
            onClick={handleSubmit}
            color="primary"
            idleText="Submit"
            loadingText="Submitting..."
            successText="Submitted!"
            errorText="Error"
            shadow={true}
            rounded={true}
            block={false}
          />
          <ReactiveButton
            buttonState={resetState}
            onClick={handleReset}
            color="secondary"
            idleText="Reset"
            loadingText="Resetting..."
            successText="Reset!"
            shadow={true}
            rounded={true}
            block={false}
          />
        </div>
      </form>
    </div>
  );
}

export default FormWithReactiveButtons;
Enter fullscreen mode Exit fullscreen mode

Update your App.jsx:

// src/App.jsx
import React from 'react';
import ReactiveButtonSystem from './ReactiveButtonSystem';
import FormWithReactiveButtons from './FormWithReactiveButtons';
import './App.css';

function App() {
  return (
    <div className="App">
      <ReactiveButtonSystem />
      <FormWithReactiveButtons />
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

This example demonstrates:

  • Different button states
  • Error handling
  • Form integration
  • Size variations
  • Multiple button instances
  • Async operations
  • State management

Common Issues / Troubleshooting

  1. Button not displaying: Make sure you're importing ReactiveButton correctly. The component should be imported from 'reactive-button'.

  2. State not changing: Ensure you're managing the buttonState in your component using useState. The state should be one of: 'idle', 'loading', 'success', 'error'.

  3. Loading state not showing: Set buttonState to 'loading' before the async operation and change it to 'success' or 'error' after completion.

  4. Click not working: Use onClick prop for event handling. Make sure the handler is properly defined and doesn't prevent default behavior if needed.

  5. Styling issues: Use the color, size, shadow, and rounded props to customize appearance. Available colors include 'primary', 'secondary', 'red', etc.

  6. State not resetting: After showing success or error state, use setTimeout to reset the state back to 'idle' after a delay.

Next Steps

Now that you have an advanced understanding of reactive-button:

  • Explore all available button colors and styles
  • Learn about advanced state management patterns
  • Implement button groups and toolbars
  • Add custom animations
  • Create button themes
  • Integrate with form libraries
  • Learn about other button libraries
  • Check the official repository: https://github.com/arifszn/reactive-button

Summary

You've successfully integrated reactive-button into your React application with advanced features including state management, error handling, form integration, and multiple button configurations. reactive-button provides a simple solution for creating reactive buttons with smooth state transitions and visual feedback.

SEO Keywords

reactive-button
React reactive button
reactive-button tutorial
React button states
reactive-button installation
React loading button
reactive-button example
React button component
reactive-button setup
React interactive button
reactive-button customization
React button library
reactive-button states
React button animations
reactive-button getting started

Top comments (0)