Skip to content

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>
  );
}
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

Released under the MIT License.