qariyb-tickets

A standalone ticket selection widget without checkout. Use this when you want to build a custom checkout flow or integrate with your own payment system.

<qariyb-tickets
  event-id="01HWXYZ123ABC456"
  on-continue="handleTicketSelection"
></qariyb-tickets>

<script>
  function handleTicketSelection(data) {
    console.log('Selected tickets:', data.cart);
    // Build your own checkout...
  }
</script>

Use Cases

  • Custom checkout flows with your own payment processor
  • Multi-step wizards where ticket selection is one step
  • Integration with existing cart/checkout systems
  • Building custom UIs around ticket data

Attributes

Required

  • Name
    event-id
    Type
    string
    Description

    The event ULID from your Qariyb dashboard.

Optional

  • Name
    theme
    Type
    'light' | 'dark' | 'flat' | 'minimal'
    Description

    Theme preset. Defaults to 'light'.

  • Name
    accent-color
    Type
    string
    Description

    Primary color in hex format. Defaults to '#10b981'.

Callback Attributes

  • Name
    on-ready
    Type
    function
    Description

    Called when component mounts. Receives { eventId }.

  • Name
    on-loaded
    Type
    function
    Description

    Called when ticket data loads. Receives { tickets, event }.

  • Name
    on-quantity-changed
    Type
    function
    Description

    Called when quantity changes. Receives { ticketId, ticketName, quantity, previousQuantity, price, currency }.

  • Name
    on-continue
    Type
    function
    Description

    Called when user clicks continue. Receives { cart, eventId }.

  • Name
    on-error
    Type
    function
    Description

    Called on error. Receives { error, eventId }.


Events

qariyb:tickets:ready

Emitted when component mounts.

interface TicketsReadyDetail {
  eventId: string;
}

qariyb:tickets:loaded

Emitted when ticket data is fetched.

interface TicketsLoadedDetail {
  tickets: TicketType[];
  event: QariybEvent;
}

interface TicketType {
  id: string;
  name: string;
  description: string | null;
  price_cents: number;
  currency: string;
  quantity_available: number | null;  // null means uncapped, not sold out
  max_per_order: number;
  min_per_order: number;
  is_free: boolean;
}
tickets.addEventListener('qariyb:tickets:loaded', (e) => {
  const { tickets, event } = e.detail.data;

  console.log('Event:', event.title);
  console.log('Available tickets:');
  tickets.forEach(t => {
    console.log(`  ${t.name}: $${t.price_cents / 100} (${t.quantity_available} left)`);
  });
});

qariyb:tickets:quantity-changed

Emitted when user changes ticket quantity.

interface TicketsQuantityChangedDetail {
  ticketId: string;
  ticketName: string;
  quantity: number;
  previousQuantity: number;
  price: number;        // In cents
  currency: string;
}
tickets.addEventListener('qariyb:tickets:quantity-changed', (e) => {
  const { ticketName, quantity, previousQuantity, price } = e.detail.data;

  if (quantity > previousQuantity) {
    analytics.track('add_to_cart', { item: ticketName, price: price / 100 });
  } else {
    analytics.track('remove_from_cart', { item: ticketName });
  }
});

qariyb:tickets:selected

Emitted when user clicks "Continue to Checkout". Triggered via on-continue attribute.

interface TicketsSelectedDetail {
  cart: Cart;
  eventId: string;
}

interface Cart {
  items: CartItem[];
  totalCents: number;
  totalQuantity: number;
  currency: string;
}

interface CartItem {
  ticketTypeId: string;
  ticketTypeName: string;
  quantity: number;
  priceCents: number;
  currency: string;
}
tickets.addEventListener('qariyb:tickets:selected', (e) => {
  const { cart, eventId } = e.detail.data;

  console.log('Ready to checkout:');
  console.log('  Total:', cart.totalCents / 100, cart.currency);
  console.log('  Items:', cart.totalQuantity);

  cart.items.forEach(item => {
    console.log(`  - ${item.ticketTypeName} x${item.quantity}`);
  });

  myCheckout.start(cart, eventId);
});

qariyb:tickets:error

Emitted when an error occurs.

interface TicketsErrorDetail {
  error: string;
  eventId: string;
}

Public Methods

getCart()

Returns the current cart state.

getCart(): Cart
const tickets = document.querySelector('qariyb-tickets');
const cart = tickets.getCart();

console.log('Current cart:', cart);
console.log('Total:', cart.totalCents / 100);
console.log('Items:', cart.items);

clearCart()

Resets the cart to empty.

clearCart(): void
const tickets = document.querySelector('qariyb-tickets');
tickets.clearCart();

Examples

Custom Checkout Integration

<qariyb-tickets
  event-id="01HWXYZ123ABC456"
  on-continue="proceedToCheckout"
></qariyb-tickets>

<div id="custom-checkout" style="display: none;">
  <!-- Your custom checkout form -->
</div>

<script>
  function proceedToCheckout(data) {
    const { cart, eventId } = data;

    // Hide tickets, show checkout
    document.querySelector('qariyb-tickets').style.display = 'none';
    document.getElementById('custom-checkout').style.display = 'block';

    // Initialize your checkout with cart data
    initMyCheckout({
      eventId: eventId,
      items: cart.items.map(item => ({
        ticketId: item.ticketTypeId,
        name: item.ticketTypeName,
        quantity: item.quantity,
        price: item.priceCents,
      })),
      total: cart.totalCents,
      currency: cart.currency,
    });
  }
</script>

Multi-Step Wizard

<div class="wizard">
  <div class="step" data-step="1">
    <h2>Step 1: Select Tickets</h2>
    <qariyb-tickets event-id="01HW..." on-continue="goToStep2"></qariyb-tickets>
  </div>

  <div class="step" data-step="2" style="display: none;">
    <h2>Step 2: Your Details</h2>
    <form id="details-form"><!-- Your custom form --></form>
  </div>

  <div class="step" data-step="3" style="display: none;">
    <h2>Step 3: Payment</h2>
    <!-- Your payment integration -->
  </div>
</div>

<script>
  let currentCart = null;

  function goToStep2(data) {
    currentCart = data.cart;
    showStep(2);
  }

  function showStep(stepNumber) {
    document.querySelectorAll('.step').forEach(s => {
      s.style.display = s.dataset.step == stepNumber ? 'block' : 'none';
    });
  }
</script>

Real-Time Cart Display

<div class="layout">
  <div class="main">
    <qariyb-tickets event-id="01HW..."></qariyb-tickets>
  </div>

  <aside class="sidebar">
    <div id="cart-summary">
      <h3>Your Selection</h3>
      <div id="cart-items">No tickets selected</div>
      <div id="cart-total"></div>
    </div>
  </aside>
</div>

<script>
  const ticketsEl = document.querySelector('qariyb-tickets');

  ticketsEl.addEventListener('qariyb:tickets:quantity-changed', () => {
    updateCartSummary();
  });

  function updateCartSummary() {
    const cart = ticketsEl.getCart();

    if (cart.totalQuantity === 0) {
      document.getElementById('cart-items').innerHTML = 'No tickets selected';
      document.getElementById('cart-total').innerHTML = '';
      return;
    }

    let html = '<ul>';
    cart.items.forEach(item => {
      html += `<li>${item.ticketTypeName} x${item.quantity} - $${(item.priceCents * item.quantity) / 100}</li>`;
    });
    html += '</ul>';

    document.getElementById('cart-items').innerHTML = html;
    document.getElementById('cart-total').innerHTML = `<strong>Total: $${cart.totalCents / 100}</strong>`;
  }
</script>

With Analytics

<qariyb-tickets
  event-id="01HWXYZ123ABC456"
  on-loaded="trackTicketsViewed"
  on-quantity-changed="trackCartChange"
  on-continue="trackCheckoutStarted"
></qariyb-tickets>

<script>
  function trackTicketsViewed(data) {
    gtag('event', 'view_item_list', {
      items: data.tickets.map(t => ({
        item_id: t.id,
        item_name: t.name,
        price: t.price_cents / 100,
      })),
    });
  }

  function trackCartChange(data) {
    const action = data.quantity > data.previousQuantity ? 'add_to_cart' : 'remove_from_cart';
    gtag('event', action, {
      items: [{
        item_id: data.ticketId,
        item_name: data.ticketName,
        price: data.price / 100,
      }],
    });
  }

  function trackCheckoutStarted(data) {
    gtag('event', 'begin_checkout', {
      value: data.cart.totalCents / 100,
      currency: data.cart.currency,
    });
  }
</script>

Styling

The tickets component uses the same styling system as other components.

window.QariybConfig = {
  publishableKey: 'pk_live_...',
  theme: 'light',
  variables: {
    colorPrimary: '#4f46e5',
  },
  rules: {
    '.TicketRow': {
      padding: '20px',
      borderRadius: '12px',
    },
    '.TicketRow--selected': {
      borderColor: '#4f46e5',
      backgroundColor: 'rgba(79, 70, 229, 0.05)',
    },
    '.QuantityButton': {
      borderRadius: '50%',
    },
  },
};

Complete Example

<!DOCTYPE html>
<html>
<head>
  <title>Select Tickets</title>
  <script>window.QariybConfig = { publishableKey: 'pk_live_...', theme: 'light' };</script>
  <script src="https://js.qariyb.com/v1/qariyb.js"></script>
  <style>
    .container { max-width: 600px; margin: 40px auto; padding: 0 20px; }
    #checkout-area { display: none; margin-top: 20px; padding: 20px; background: #f9fafb; border-radius: 8px; }
  </style>
</head>
<body>
  <div class="container">
    <h1>Event Registration</h1>

    <qariyb-tickets
      id="ticket-selector"
      event-id="01HWXYZ123ABC456"
      on-continue="showCheckout"
    ></qariyb-tickets>

    <div id="checkout-area">
      <h2>Complete Registration</h2>
      <p id="summary"></p>
      <form id="checkout-form">
        <input type="text" placeholder="Full Name" required>
        <input type="email" placeholder="Email" required>
        <button type="submit">Complete Registration</button>
      </form>
    </div>
  </div>

  <script>
    let selectedCart = null;

    function showCheckout(data) {
      selectedCart = data.cart;
      document.getElementById('summary').textContent =
        `${selectedCart.totalQuantity} ticket(s) - $${selectedCart.totalCents / 100}`;
      document.getElementById('checkout-area').style.display = 'block';
    }

    document.getElementById('checkout-form').addEventListener('submit', async (e) => {
      e.preventDefault();
      console.log('Processing:', selectedCart);
    });
  </script>
</body>
</html>

Was this page helpful?