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>