Event Modifiers Examples
Learn how to use event modifiers to control event behavior and prevent common issues.
Basic Modifiers
Prevent Default Behavior
html
<!-- Prevent form submission default -->
<form data-fanfest-track="form_submit" data-fanfest-on="submit:prevent">
<input type="email" required />
<button type="submit">Subscribe</button>
</form>jsx
// React: Prevent default with tracking
function FormWithTracking() {
const handleSubmit = async (event) => {
event.preventDefault(); // Manual prevent default
await FanFestSDK.trackEvent({
action: "form_submit",
description: "Newsletter Signup",
});
// Handle form submission
submitForm();
};
return (
<form onSubmit={handleSubmit}>
<input type="email" required />
<button type="submit">Subscribe</button>
</form>
);
}Fire Only Once
html
<!-- Track only the first click -->
<button
data-fanfest-track="first_click"
data-fanfest-on="click:once"
data-fanfest-description="First Click"
>
Click Me
</button>jsx
// React: One-time tracking
function OneTimeButton() {
const [hasTracked, setHasTracked] = useState(false);
const handleClick = async () => {
if (!hasTracked) {
await FanFestSDK.trackEvent({
action: "first_click",
description: "First Click",
});
setHasTracked(true);
}
// Handle the click
handleButtonClick();
};
return <button onClick={handleClick}>Click Me</button>;
}Stop Event Propagation
html
<!-- Stop event from bubbling up -->
<button
data-fanfest-track="isolated_click"
data-fanfest-on="click:stop"
data-fanfest-description="Isolated Click"
>
Isolated Button
</button>jsx
// React: Stop propagation
function IsolatedButton() {
const handleClick = async (event) => {
event.stopPropagation(); // Manual stop propagation
await FanFestSDK.trackEvent({
action: "isolated_click",
description: "Isolated Click",
});
// Handle the click
handleButtonClick();
};
return <button onClick={handleClick}>Isolated Button</button>;
}Capture Phase Events
html
<!-- Use capture phase for early interception -->
<button
data-fanfest-track="early_capture"
data-fanfest-on="click:capture"
data-fanfest-description="Early Capture"
>
Capture Button
</button>Combined Modifiers
Prevent + Once
html
<!-- Prevent default and fire only once -->
<button
data-fanfest-track="submit_once"
data-fanfest-on="click:prevent:once"
data-fanfest-description="Submit Once"
>
Submit (One Time)
</button>jsx
// React: Prevent default and track once
function SubmitOnceButton() {
const [hasSubmitted, setHasSubmitted] = useState(false);
const handleClick = async (event) => {
event.preventDefault(); // Prevent default
if (!hasSubmitted) {
await FanFestSDK.trackEvent({
action: "submit_once",
description: "Submit Once",
});
setHasSubmitted(true);
}
// Handle submission
handleSubmission();
};
return <button onClick={handleClick}>Submit (One Time)</button>;
}Stop + Prevent
html
<!-- Stop propagation and prevent default -->
<button
data-fanfest-track="isolated_submit"
data-fanfest-on="click:stop:prevent"
data-fanfest-description="Isolated Submit"
>
Isolated Submit
</button>jsx
// React: Stop propagation and prevent default
function IsolatedSubmitButton() {
const handleClick = async (event) => {
event.stopPropagation();
event.preventDefault();
await FanFestSDK.trackEvent({
action: "isolated_submit",
description: "Isolated Submit",
});
// Handle the submission
handleSubmission();
};
return <button onClick={handleClick}>Isolated Submit</button>;
}All Modifiers Combined
html
<!-- Use all modifiers together -->
<button
data-fanfest-track="complete_tracking"
data-fanfest-on="click:prevent:once:stop:capture"
data-fanfest-description="Complete Tracking"
>
Complete Button
</button>Real-World Examples
Newsletter Signup Form
html
<!-- Newsletter signup with modifiers -->
<form
data-fanfest-track="newsletter_signup"
data-fanfest-on="submit:prevent:once"
data-fanfest-description="Newsletter Signup"
data-fanfest-object-id="newsletter-form"
>
<input type="email" placeholder="Enter your email" required />
<button type="submit">Subscribe</button>
</form>jsx
// React: Newsletter signup
function NewsletterForm() {
const [isSubmitting, setIsSubmitting] = useState(false);
const handleSubmit = async (event) => {
event.preventDefault();
if (isSubmitting) return; // Prevent double submission
setIsSubmitting(true);
try {
await FanFestSDK.trackEvent({
action: "newsletter_signup",
description: "Newsletter Signup",
});
await submitNewsletter();
} catch (error) {
console.error("Newsletter signup failed:", error);
} finally {
setIsSubmitting(false);
}
};
return (
<form onSubmit={handleSubmit}>
<input type="email" required />
<button type="submit" disabled={isSubmitting}>
{isSubmitting ? "Subscribing..." : "Subscribe"}
</button>
</form>
);
}Product Purchase Button
html
<!-- Purchase button with modifiers -->
<button
data-fanfest-track="purchase"
data-fanfest-on="click:prevent:once"
data-fanfest-description="Product Purchase"
data-fanfest-object-id="product-123"
data-fanfest-meta-amount="99.99"
>
Buy Now - $99.99
</button>jsx
// React: Purchase button
function PurchaseButton({ product }) {
const [isPurchasing, setIsPurchasing] = useState(false);
const handlePurchase = async (event) => {
event.preventDefault();
if (isPurchasing) return; // Prevent double purchase
setIsPurchasing(true);
try {
await FanFestSDK.trackEvent({
action: "purchase",
description: "Product Purchase",
externalObjectId: product.id,
metadata: {
amount: product.price,
currency: "USD",
},
});
await processPurchase(product);
} catch (error) {
console.error("Purchase failed:", error);
} finally {
setIsPurchasing(false);
}
};
return (
<button
onClick={handlePurchase}
disabled={isPurchasing}
className="purchase-button"
>
{isPurchasing ? "Processing..." : `Buy Now - $${product.price}`}
</button>
);
}Modal Close Button
html
<!-- Modal close with stop propagation -->
<button
data-fanfest-track="modal_close"
data-fanfest-on="click:stop"
data-fanfest-description="Modal Close"
data-fanfest-object-id="modal-1"
>
×
</button>jsx
// React: Modal close button
function ModalCloseButton({ onClose }) {
const handleClose = async (event) => {
event.stopPropagation(); // Prevent modal from closing
await FanFestSDK.trackEvent({
action: "modal_close",
description: "Modal Close",
});
onClose();
};
return (
<button onClick={handleClose} className="modal-close">
×
</button>
);
}Advanced Patterns
Conditional Modifiers
jsx
function ConditionalButton({ user, product }) {
const handleClick = async (event) => {
// Apply modifiers based on user state
if (!user.isLoggedIn) {
event.preventDefault(); // Prevent purchase for anonymous users
}
await FanFestSDK.trackEvent({
action: "purchase_attempt",
description: "Purchase Attempt",
externalObjectId: product.id,
metadata: {
userType: user.isLoggedIn ? "authenticated" : "anonymous",
},
});
if (user.isLoggedIn) {
handlePurchase(product);
} else {
redirectToLogin();
}
};
return (
<button onClick={handleClick}>
{user.isLoggedIn ? "Buy Now" : "Sign In to Purchase"}
</button>
);
}Dynamic Modifier Application
jsx
function DynamicButton({ config }) {
const handleClick = async (event) => {
// Apply modifiers based on configuration
if (config.preventDefault) {
event.preventDefault();
}
if (config.stopPropagation) {
event.stopPropagation();
}
await FanFestSDK.trackEvent({
action: config.action,
description: config.description,
});
// Handle the click
config.onClick();
};
return <button onClick={handleClick}>{config.label}</button>;
}Error Handling with Modifiers
Retry Logic with Once Modifier
jsx
function RetryButton() {
const [retryCount, setRetryCount] = useState(0);
const [hasTracked, setHasTracked] = useState(false);
const handleClick = async () => {
if (!hasTracked) {
await FanFestSDK.trackEvent({
action: "retry_click",
description: "Retry Button Click",
metadata: { retryCount },
});
setHasTracked(true);
}
try {
await performAction();
} catch (error) {
setRetryCount((prev) => prev + 1);
// Retry logic
}
};
return <button onClick={handleClick}>Retry ({retryCount} attempts)</button>;
}Next Steps
- Metadata & Deduping - Data management
- Click Tracking - User interaction tracking
- Page Views - Page navigation tracking
