Skip to content

Clicker Button Component

A reusable button component that emits click events for component-to-component communication.

Overview

Component Name: clicker-buttonLatest Version: 1.0.0Author: BoardAPI Team License: MIT

The Clicker Button is a simple interactive button that emits action:click events when clicked. It's perfect for triggering actions in other components on the board.

Use Cases

  • Triggering animations in other components
  • Game mechanics (score counting, balloon popping, etc.)
  • Interactive tutorials and demos
  • User input collection
  • Event-driven workflows

Component Preview

┌───────────────────┐
│                   │
│   [Click Me!]     │
│                   │
│   Clicks: 5/10    │
│                   │
└───────────────────┘

Props Schema

PropTypeRequiredDefaultDescription
buttonTextstringNo"" (empty)Custom button label text
maxClicksnumberNo10Maximum clicks before auto-reset

Props Examples

Default button:

json
{
  "buttonText": "",
  "maxClicks": 10
}

Custom label:

json
{
  "buttonText": "Pop the Balloon!",
  "maxClicks": 5
}

Unlimited clicks:

json
{
  "buttonText": "Click Me",
  "maxClicks": -1
}

Events

Emitted Events

action:click

Fired every time the button is clicked.

Event Structure:

javascript
{
  type: 'component-event',
  event: 'action:click',
  data: {
    clickCount: 5,        // Current click count
    maxClicks: 10,        // Maximum clicks before reset
    timestamp: 1700000000 // Unix timestamp
  }
}

Example Usage:

javascript
// In another component - listen for clicks
window.addEventListener('message', (event) => {
  if (event.data.type === 'board-event' &&
      event.data.event === 'action:click') {

    const { clickCount, maxClicks } = event.data.data;
    console.log(`Click ${clickCount} of ${maxClicks}`);

    // Do something with the click event
    updateCounter(clickCount);
  }
});

Listened Events

This component does not listen to any events. It only emits events.

Dimensions

  • Width: 200px
  • Height: 360px
  • Resizable: No

manifest.json

json
{
  "name": "clicker-button",
  "version": "1.0.0",
  "description": "Clickable button that emits action events",
  "author": "BoardAPI Team",
  "license": "MIT",
  "entry": "index.html",
  "component": {
    "width": 200,
    "height": 360,
    "resizable": false,
    "schema": {
      "type": "object",
      "properties": {
        "buttonText": {
          "type": "string",
          "default": "",
          "description": "Button label text"
        },
        "maxClicks": {
          "type": "number",
          "default": 10,
          "description": "Max clicks before reset (-1 for unlimited)"
        }
      }
    }
  }
}

Implementation Example

index.html (Simplified)

html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
    body {
      margin: 0;
      padding: 20px;
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
      display: flex;
      flex-direction: column;
      align-items: center;
      justify-content: center;
      height: 100vh;
      background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
      color: white;
    }

    .click-button {
      padding: 16px 32px;
      font-size: 18px;
      font-weight: bold;
      background: white;
      color: #667eea;
      border: none;
      border-radius: 8px;
      cursor: pointer;
      transition: transform 0.2s;
    }

    .click-button:hover {
      transform: scale(1.05);
    }

    .click-button:active {
      transform: scale(0.95);
    }

    .counter {
      margin-top: 20px;
      font-size: 16px;
    }
  </style>
</head>
<body>
  <button class="click-button" id="clickBtn">Click Me!</button>
  <div class="counter" id="counter">Clicks: 0/10</div>

  <script>
    // Get props from parent
    let props = window.componentProps || {};
    const maxClicks = props.maxClicks || 10;
    const buttonText = props.buttonText || 'Click Me!';

    // State
    let clickCount = 0;

    // Update button text
    document.getElementById('clickBtn').textContent = buttonText;

    // Update counter display
    function updateCounter() {
      const counterText = maxClicks > 0
        ? `Clicks: ${clickCount}/${maxClicks}`
        : `Clicks: ${clickCount}`;
      document.getElementById('counter').textContent = counterText;
    }

    // Handle button click
    document.getElementById('clickBtn').addEventListener('click', () => {
      clickCount++;
      updateCounter();

      // Emit event to board
      window.parent.postMessage({
        type: 'component-event',
        event: 'action:click',
        data: {
          clickCount,
          maxClicks,
          timestamp: Date.now()
        }
      }, '*');

      // Auto-reset if maxClicks reached
      if (maxClicks > 0 && clickCount >= maxClicks) {
        setTimeout(() => {
          clickCount = 0;
          updateCounter();
        }, 500);
      }
    });

    // Initialize
    updateCounter();
  </script>
</body>
</html>

Usage on a Board

Adding via API

bash
curl -X POST http://localhost:4000/api/v1/boards/{boardId}/objects \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "objectId": "clicker-btn-1",
    "type": "external-component",
    "position": { "x": 100, "y": 100 },
    "width": 200,
    "height": 360,
    "data": {
      "componentUrl": "http://localhost:4000/components/clicker-button@1.0.0/index.html",
      "props": {
        "buttonText": "Click to Pop!",
        "maxClicks": 10
      }
    }
  }'

Combining with Other Components

Example: Balloon Game

Combine with balloon-viewer and score-display for an interactive game:

json
{
  "objects": [
    {
      "objectId": "clicker-btn-1",
      "type": "external-component",
      "position": { "x": 70, "y": 100 },
      "data": {
        "componentUrl": ".../clicker-button@1.0.0/index.html",
        "props": { "buttonText": "", "maxClicks": 10 }
      }
    },
    {
      "objectId": "balloon-1",
      "type": "external-component",
      "position": { "x": 290, "y": 100 },
      "data": {
        "componentUrl": ".../balloon-viewer@1.0.0/index.html",
        "props": { "balloonColor": "#f56565", "maxSize": 10 }
      }
    },
    {
      "objectId": "score-1",
      "type": "external-component",
      "position": { "x": 590, "y": 100 },
      "data": {
        "componentUrl": ".../score-display@1.0.0/index.html",
        "props": { "label": "" }
      }
    }
  ]
}

See: Balloon Game Tutorial

Customization Ideas

Visual Themes

Change the gradient and button colors:

css
body {
  background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}

.click-button {
  background: #ffd93d;
  color: #333;
}

Animation Effects

Add pulse animation on click:

css
@keyframes pulse {
  0% { transform: scale(1); }
  50% { transform: scale(1.1); }
  100% { transform: scale(1); }
}

.click-button.clicked {
  animation: pulse 0.3s ease;
}

Sound Effects

Add click sound using Web Audio API:

javascript
function playClickSound() {
  const audioContext = new AudioContext();
  const oscillator = audioContext.createOscillator();
  const gainNode = audioContext.createGain();

  oscillator.connect(gainNode);
  gainNode.connect(audioContext.destination);

  oscillator.frequency.value = 800;
  oscillator.type = 'sine';
  gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
  gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.1);

  oscillator.start(audioContext.currentTime);
  oscillator.stop(audioContext.currentTime + 0.1);
}

Testing

Unit Test (Jest)

javascript
describe('Clicker Button Component', () => {
  test('emits action:click event on button click', () => {
    const postMessageSpy = jest.spyOn(window.parent, 'postMessage');

    const button = document.getElementById('clickBtn');
    button.click();

    expect(postMessageSpy).toHaveBeenCalledWith(
      expect.objectContaining({
        type: 'component-event',
        event: 'action:click',
        data: expect.objectContaining({
          clickCount: 1,
          maxClicks: 10
        })
      }),
      '*'
    );
  });

  test('resets after maxClicks reached', (done) => {
    const button = document.getElementById('clickBtn');

    // Click 10 times
    for (let i = 0; i < 10; i++) {
      button.click();
    }

    // Wait for auto-reset
    setTimeout(() => {
      expect(clickCount).toBe(0);
      done();
    }, 600);
  });
});

Download


Next: Balloon Viewer Component