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
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
buttonText | string | No | "" (empty) | Custom button label text |
maxClicks | number | No | 10 | Maximum 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": "" }
}
}
]
}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);
});
});Related Components
- Balloon Viewer - Balloon that grows on clicks
- Score Display - Score counter
- Progress Bar - Visual progress indicator
Related Documentation
Download
- Source Code: clicker-button-1.0.0.zip
- Live Demo: Try it on BoardAPI
Next: Balloon Viewer Component