Skip to content

<seva-event-register-cta>

The <seva-event-register-cta> component is the on-page anchor for registration state on a Webflow event page. It renders a single CTA whose label and behavior reflect the current user’s relationship to the event: not registered, registered, or declined.

This is the recommended entry point for embedding registration on a Webflow event detail page that already shows event information itself. Instead of duplicating the event header / dates / description, the CTA renders just the action surface:

StateWhat renders
Pre-registrationA “Register” button (or “Continue Registration” if a cart item already exists for this event), an optional late-fee notice, and — if signed in — a “Decline” button.
RegisteredA summary card via <seva-event-registration-status> with attendees, ticket details, and Add Guests / Cancel actions.
DeclinedA “You’ve declined this event” message with a “Register Instead” affordance.

This is an inline component — it reads the auth token from localStorage (written by <seva-auth> or any modal component). It does not own any auth UI itself. The user signs in inside the <seva-event-register-modal> that the CTA opens.

The CTA does not display event details (title, dates, location) — your page is expected to render those. If you want the form to render its own event header, use <seva-event-register> directly instead.

<script
type="module"
src="YOUR_COMPONENTS_URL/seva-event-register-cta.js"
></script>
<script
type="module"
src="YOUR_COMPONENTS_URL/seva-event-register-modal.js"
></script>
<seva-event-register-cta
event-slug="annual-gala"
tenant-slug="my-club"
api-url="https://api.seva.tools"
>
</seva-event-register-cta>
<!-- Modal must also be on the page; CTA opens it via seva:open-registration. -->
<seva-event-register-modal
tenant-slug="my-club"
api-url="https://api.seva.tools"
>
</seva-event-register-modal>

The CTA dispatches seva:open-registration on document when the user clicks Register; the modal listens for that event and opens itself. Both components must be present on the same page for the flow to work.

AttributeTypeDefaultDescription
event-slugstring''Required. Slug of the event to display registration state for. Updating this attribute triggers a re-fetch.
tenant-slugstring''Required. Your organization’s tenant slug; scopes API calls and localStorage keys.
api-urlstring'https://api.seva.tools'Base URL of the Seva API.
theme'light' | 'dark''light'Color theme.

All events are dispatched on document and bubble through the Shadow DOM.

EventDetailWhen it fires
seva:open-registration{ eventSlug, view? }User clicks the primary “Register” / “Continue Registration” button, or chooses “Add Guests” from the registered-state card (in which case view: 'guest-info' is included). The modal listens for this event.
seva:registration-canceled{ eventSlug }After the cancel-registration API call returns. Other CTAs and the modal listen for this.
seva:registration-declined{ eventSlug }After the user clicks “Decline” and the API call returns.

The CTA also dispatches seva:open-my-registrations (no payload) when an authenticated user clicks the “View All My Registrations” link beneath the action buttons — to be picked up by an <seva-my-registrations> element if one is on the page.

The CTA subscribes to seven document-level events to keep its rendered state in sync with auth, cart, and registration changes:

EventEffect
seva:authenticatedStores the user/token and re-fetches event + registration state.
seva:signed-outClears the user/token and re-fetches state (becomes anonymous view).
seva:registration-completedRe-fetches; transitions to the “registered” view.
seva:registration-canceledRe-fetches; returns to the “pre-registration” view.
seva:registration-declinedRe-fetches; transitions to the “declined” view.
seva:cart-updatedReloads the cart store; updates button label between “Register” and “Continue Registration”.
seva:add-to-cartSame as seva:cart-updated.
seva:checkout-completeRe-fetches the registration — this is the authoritative happy-path signal that a cart item became a real registration.
  • Renders nothing in three cases: the event slug returns 404 from the API, the event has already ended, or the initial load is in flight. The 404 branch is silent by design (no error UI on the page) so a typo’d event-slug produces an empty space rather than a visible error. A console-warn breadcrumb for misconfigured slugs is tracked in TODOS.md (entry #136).
  • Late-fee notice is shown automatically if the event has a configured late fee. The wording adapts based on whether the deadline has passed and whether the late fee applies to the registrant, guests, both, or a mixed catalog.
  • Decline button is shown only when the user is authenticated and event.showDeclineButton !== false. The label can be customized via the event’s declineButtonLabel.
  • The CTA never renders the registration form itself. All sign-in, attendee selection, and ticket choice happens inside the modal it opens.

The CTA is one piece of a small ecosystem:

  • <seva-event-register-modal> — required. The CTA opens it via seva:open-registration; the modal contains the actual registration form.
  • <seva-event-register> — the underlying form, embedded inside the modal. You usually do not place this on the page directly when using the CTA pattern.
  • <seva-cart> / <seva-cart-drawer> — the CTA flips its label to “Continue Registration” when the cart already contains an item for this event.
  • <seva-event-registration-status> — internal sub-component that renders the post-registration card. You don’t embed it directly; the CTA does so when in the “registered” view.

A Webflow event detail page with the CTA, modal, cart, and cart drawer wired together:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Annual Gala — My Club</title>
<script
type="module"
src="YOUR_COMPONENTS_URL/seva-event-register-cta.js"
></script>
<script
type="module"
src="YOUR_COMPONENTS_URL/seva-event-register-modal.js"
></script>
<script type="module" src="YOUR_COMPONENTS_URL/seva-cart.js"></script>
<script
type="module"
src="YOUR_COMPONENTS_URL/seva-cart-drawer.js"
></script>
</head>
<body>
<!-- Your Webflow event header / hero / description -->
<h1>Annual Gala</h1>
<p>Join us for the biggest fundraiser of the year…</p>
<!-- Registration anchor -->
<seva-event-register-cta
event-slug="annual-gala"
tenant-slug="my-club"
api-url="https://api.seva.tools"
>
</seva-event-register-cta>
<!-- Modal that the CTA opens (must be in the DOM) -->
<seva-event-register-modal
tenant-slug="my-club"
api-url="https://api.seva.tools"
>
</seva-event-register-modal>
<!-- Cart icon (optional) and drawer for checkout -->
<seva-cart tenant-slug="my-club" api-url="https://api.seva.tools">
</seva-cart>
<seva-cart-drawer tenant-slug="my-club" api-url="https://api.seva.tools">
</seva-cart-drawer>
</body>
</html>

See Wiring components together for a diagram of how these elements coordinate via document events.