npm package: @mobiloud/ml-back-button
Description: Customizable back button widget with SPA navigation tracking for any website
Author: MobiLoud
Latest version: 1.1.0

# ml-back-button

A lightweight, customizable back button widget with automatic SPA (Single Page Application) navigation tracking. Works on any website with zero dependencies.

## Features

- **SPA Ready** - Automatically tracks `pushState` and `replaceState` for seamless single-page application integration
- **Smart Visibility** - Only shows when there's navigation history in the current session
- **Loading States** - Built-in spinner with configurable minimum display time
- **Fully Customizable** - Position, colors, text, icons - everything can be tailored to your needs
- **Icon-Only Mode** - Create compact squared buttons with SVG icon support (perfect for Font Awesome icons)
- **Singleton Pattern** - Only one instance per page, prevents conflicts
- **Event Callbacks** - React to show, hide, and back button click events
- **Responsive** - Works great on mobile and desktop devices
- **Zero Dependencies** - Pure vanilla JavaScript, no frameworks required
- **Lightweight** - Minimal footprint, maximum performance

## Browser Compatibility

Works in all modern browsers that support:
- ES6+ JavaScript
- History API (`pushState`, `replaceState`, `popstate`)
- CSS3 (transitions, flexbox)

Tested on:
- Chrome 90+
- Firefox 88+
- Safari 14+
- Edge 90+

## Installation

### Option 1: CDN (Recommended)

Include the script directly from npm using a CDN:

```html
<!-- Using unpkg CDN -->
<script src="https://unpkg.com/@mobiloud/ml-back-button/script.js"></script>

<!-- OR using jsDelivr CDN -->
<script src="https://cdn.jsdelivr.net/npm/@mobiloud/ml-back-button/script.js"></script>
```

### Option 2: NPM Install

Install via npm and include the script:

```bash
npm install @mobiloud/ml-back-button
```

Then include it in your HTML:

```html
<script src="node_modules/@mobiloud/ml-back-button/script.js"></script>
```

### Option 3: Direct Download

Download `script.js` and include it in your HTML:

```html
<script src="path/to/script.js"></script>
```

## Quick Start

### Basic Usage

```html
<!DOCTYPE html>
<html>
<head>
    <title>My Website</title>
</head>
<body>
    <h1>Welcome</h1>

    <!-- Your content -->

    <!-- Include the widget from CDN -->
    <script src="https://unpkg.com/@mobiloud/ml-back-button/script.js"></script>

    <!-- Initialize with defaults -->
    <script>
        createBackButton();
    </script>
</body>
</html>
```

That's it! The back button will automatically appear in the top-left corner after the first navigation.

## Configuration Options

All configuration options are optional. Here's the complete configuration object with default values:

```javascript
createBackButton({
    // Display options
    text: 'Back',              // Button text
    icon: '←',                 // Icon character, emoji, or SVG string
    showSpinner: true,         // Show loading spinner when navigating
    iconOnly: false,           // Icon-only mode (squared button, no text)
    size: 48,                  // Button size in pixels (only for iconOnly mode)

    // Position
    position: {
        vertical: 'top',       // 'top' or 'bottom'
        horizontal: 'left',    // 'left' or 'right'
        offsetTop: 20,         // Distance from top (px)
        offsetBottom: 20,      // Distance from bottom (px)
        offsetLeft: 20,        // Distance from left (px)
        offsetRight: 20        // Distance from right (px)
    },

    // Colors
    colors: {
        background: '#007bff',        // Background color
        backgroundHover: '#0056b3',   // Background on hover
        text: 'white',                // Text color
        icon: 'white',                // Icon color
        spinner: 'white'              // Spinner color
    },

    // Behavior
    minLoadingTime: 300,      // Minimum loading spinner display time (ms)

    // Callbacks
    onBack: null,             // Function called when back button is clicked
    onShow: null,             // Function called when button becomes visible
    onHide: null,             // Function called when button becomes hidden

    // Debug
    debugMode: false          // Enable console logging
});
```

## Usage Examples

### Example 1: Custom Position

```javascript
// Bottom-right corner
createBackButton({
    position: {
        vertical: 'bottom',
        horizontal: 'right',
        offsetBottom: 30,
        offsetRight: 30
    }
});
```

### Example 2: Custom Colors

```javascript
// Dark theme
createBackButton({
    colors: {
        background: '#2c3e50',
        backgroundHover: '#34495e',
        text: '#ecf0f1',
        icon: '#ecf0f1',
        spinner: '#ecf0f1'
    }
});
```

### Example 3: Custom Text and Icon

```javascript
// Different text styles
createBackButton({
    text: 'Return',
    icon: '↶'
});

// Emoji icons
createBackButton({
    text: 'Go Back',
    icon: '⬅️'
});

// Unicode symbols
createBackButton({
    text: 'Previous',
    icon: '«'
});
```

### Example 4: With Callbacks

```javascript
createBackButton({
    onBack: () => {
        console.log('User clicked back button');
        // Track analytics, save state, etc.
    },
    onShow: () => {
        console.log('Back button is now visible');
    },
    onHide: () => {
        console.log('Back button is now hidden');
    }
});
```

### Example 5: Disable Loading Spinner

```javascript
createBackButton({
    showSpinner: false
});
```

### Example 6: Debug Mode

```javascript
// Enable detailed console logging
createBackButton({
    debugMode: true
});
```

### Example 7: Complete Custom Configuration

```javascript
createBackButton({
    text: 'Previous Page',
    icon: '◀',
    showSpinner: true,
    position: {
        vertical: 'bottom',
        horizontal: 'right',
        offsetBottom: 40,
        offsetRight: 40
    },
    colors: {
        background: '#6c757d',
        backgroundHover: '#5a6268',
        text: 'white'
    },
    minLoadingTime: 500,
    onBack: () => {
        console.log('Navigation triggered');
    },
    debugMode: false
});
```

### Example 8: Icon-Only Mode (Squared Button)

```javascript
// Compact squared button with text icon
createBackButton({
    iconOnly: true,
    icon: '←',
    size: 48,  // Button size (width & height in pixels)
    position: {
        vertical: 'bottom',
        horizontal: 'left',
        offsetBottom: 20,
        offsetLeft: 20
    },
    colors: {
        background: '#2b397f',
        backgroundHover: '#1e2854',
        icon: 'white'
    }
});
```

### Example 9: Icon-Only with Font Awesome SVG

```javascript
// Squared button with Font Awesome chevron-left icon
createBackButton({
    iconOnly: true,
    size: 52,  // Slightly larger button
    icon: '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><path d="M169.4 297.4C156.9 309.9 156.9 330.2 169.4 342.7L361.4 534.7C373.9 547.2 394.2 547.2 406.7 534.7C419.2 522.2 419.2 501.9 406.7 489.4L237.3 320L406.6 150.6C419.1 138.1 419.1 117.8 406.6 105.3C394.1 92.8 373.8 92.8 361.3 105.3L169.3 297.3z"/></svg>',
    position: {
        vertical: 'bottom',
        horizontal: 'left',
        offsetBottom: 20,
        offsetLeft: 20
    },
    colors: {
        background: '#2b397f',
        backgroundHover: '#1e2854',
        icon: 'white'
    }
});
```

### Example 10: Icon-Only with Custom Size

```javascript
// Small squared button (32px)
createBackButton({
    iconOnly: true,
    size: 32,
    icon: '←',
    position: {
        vertical: 'top',
        horizontal: 'right',
        offsetTop: 10,
        offsetRight: 10
    },
    colors: {
        background: '#000',
        backgroundHover: '#333',
        icon: '#fff'
    }
});

// Large squared button (64px)
createBackButton({
    iconOnly: true,
    size: 64,
    icon: '⬅',
    position: {
        vertical: 'bottom',
        horizontal: 'left'
    }
});
```

## SPA Integration

The widget automatically detects SPA navigation patterns. It works seamlessly with:

### React Router

First, include the script in your HTML:

```html
<script src="https://unpkg.com/@mobiloud/ml-back-button/script.js"></script>
```

Then in your React app:

```javascript
// In your React app
import { useEffect } from 'react';

function App() {
    useEffect(() => {
        // Make sure the script is loaded first
        if (window.createBackButton) {
            createBackButton({
                colors: {
                    background: '#61dafb',
                    backgroundHover: '#4fa8c5'
                }
            });
        }
    }, []);

    return <YourApp />;
}
```

### Vue Router

First, include the script in your HTML:

```html
<script src="https://unpkg.com/@mobiloud/ml-back-button/script.js"></script>
```

Then in your Vue app:

```javascript
// In your Vue app
export default {
    mounted() {
        // Make sure the script is loaded first
        if (window.createBackButton) {
            createBackButton({
                colors: {
                    background: '#42b883',
                    backgroundHover: '#35925f'
                }
            });
        }
    }
}
```

### Angular Router

First, include the script in your HTML:

```html
<script src="https://unpkg.com/@mobiloud/ml-back-button/script.js"></script>
```

Then in your Angular component:

```typescript
// In your Angular component
import { Component, OnInit } from '@angular/core';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
    ngOnInit() {
        // Make sure the script is loaded first
        if ((window as any).createBackButton) {
            (window as any).createBackButton({
                colors: {
                    background: '#dd0031',
                    backgroundHover: '#b80028'
                }
            });
        }
    }
}
```

### Vanilla JavaScript SPA

```javascript
// Your SPA navigation function
function navigateTo(page) {
    // Update URL
    history.pushState({ page }, '', `/${page}`);

    // Render page content
    renderPage(page);

    // The back button automatically tracks this!
}

// Initialize back button
createBackButton();
```

## API Reference

### createBackButton(config)

Creates and initializes a back button instance. If an instance already exists, it will be destroyed and replaced.

**Parameters:**
- `config` (Object, optional) - Configuration object

**Returns:**
- BackButton instance

**Example:**
```javascript
const backButton = createBackButton({ debugMode: true });
```

### BackButton.destroy()

Destroys the current back button instance, removes it from the DOM, and cleans up all event listeners.

**Example:**
```javascript
const backButton = createBackButton();

// Later...
backButton.destroy();
```

### window.BackButtonInstance

Global reference to the current back button instance. Useful for accessing the instance from anywhere in your code.

**Example:**
```javascript
// Check if instance exists
if (window.BackButtonInstance) {
    console.log('Back button is active');
}

// Destroy from anywhere
window.BackButtonInstance.destroy();
```

## How It Works

### Navigation Tracking

The widget uses a sophisticated tracking system:

1. **Initial Load** - Records the entry URL when initialized
2. **pushState Detection** - Intercepts `history.pushState()` calls to track forward navigation
3. **replaceState Detection** - Intercepts `history.replaceState()` to update current page without adding to history
4. **popstate Events** - Listens for browser back/forward button usage
5. **Session History** - Maintains an array of visited pages in the current session

### Visibility Logic

The back button shows when:
- There are 2+ pages in the session history
- User has navigated away from the entry page

The back button hides when:
- User returns to the entry page
- Session history has only 1 page

### Loading State

When the back button is clicked:
1. Shows loading spinner (if enabled)
2. Disables the button temporarily
3. Calls `history.back()`
4. Waits for `popstate` event
5. Keeps spinner visible for minimum time (default 300ms)
6. Re-enables the button

## Troubleshooting

### Back button not appearing

**Issue:** Button doesn't show after navigation

**Solutions:**
- Check that you're using `history.pushState()` for navigation (not just changing `window.location.href`)
- Ensure the script is loaded before any navigation occurs
- Enable debug mode to see console logs: `createBackButton({ debugMode: true })`
- Check browser console for errors

### Back button in wrong position

**Issue:** Button overlaps with site content

**Solutions:**
- Adjust position offsets:
```javascript
createBackButton({
    position: {
        vertical: 'bottom',
        horizontal: 'right',
        offsetBottom: 100,  // Increase offset
        offsetRight: 30
    }
});
```
- Change z-index if needed (button uses `z-index: 999999` by default)

### Conflicts with existing code

**Issue:** Back button interferes with site functionality

**Solutions:**
- The widget uses a singleton pattern, so multiple calls to `createBackButton()` will replace the previous instance
- If you need to temporarily disable, call `.destroy()`:
```javascript
window.BackButtonInstance.destroy();
```
- Namespace conflicts are unlikely as everything is scoped within the IIFE

### Spinner not showing

**Issue:** Loading spinner doesn't appear

**Solutions:**
- Check that `showSpinner` is not set to `false`
- Verify the spinner color isn't the same as the background:
```javascript
createBackButton({
    colors: {
        background: '#007bff',
        spinner: 'white'  // Must contrast with background
    }
});
```

### History tracking issues

**Issue:** History tracking seems incorrect

**Solutions:**
- Enable debug mode to see what's being tracked:
```javascript
createBackButton({ debugMode: true });
```
- Check that you're not mixing `pushState` with full page reloads
- Ensure you're not calling `history.back()` directly elsewhere in your code

## Examples

See the following files for complete working examples:

- **widget.html** - Comprehensive demo with all customization options
- **test.html** - Simple test page with basic navigation
- **spa-test.html** - Full SPA simulation with multiple pages

## Development

### Running Examples Locally

1. Clone or download this repository
2. Open any HTML file directly in your browser:
   - `widget.html` - Interactive demo with all features
   - `test.html` - Basic functionality test
   - `spa-test.html` - SPA navigation simulation

No build process or server required!

### Modifying the Widget

The widget is contained entirely in `script.js`. Key sections:

- **Lines 1-31**: Documentation and usage comments
- **Lines 41-72**: Constructor and initialization
- **Lines 74-111**: Configuration merging
- **Lines 130-232**: Styles injection
- **Lines 234-274**: Button creation
- **Lines 329-381**: Navigation tracking (pushState/replaceState)
- **Lines 390-424**: Visibility management
- **Lines 446-492**: Back button click handler

### Debug Mode

Enable debug mode to see detailed console logs:

```javascript
createBackButton({ debugMode: true });
```

This will log:
- Initialization details
- Navigation events (pushState, replaceState, popstate)
- Button visibility changes
- Button clicks
- Loading state changes

## License

MIT License - feel free to use in personal and commercial projects.

## Support

For issues, questions, or contributions:
- Open an issue on GitHub
- Submit a pull request
- Contact the maintainers

## Credits

Created with care for the web development community.

---

**Version:** 1.0.0
**Last Updated:** 2025-10-09