Skip to content

<seva-event-register-modal>

The <seva-event-register-modal> component is a thin portal-based wrapper around <seva-event-register>. It opens in response to a document-level event and contains the full registration flow — sign-in, attendee selection, ticket choice, and confirm — inside a centered modal.

The modal exists to decouple the registration form from whatever opens it. Common pairings:

  • Webflow event detail page: <seva-event-register-cta> renders an inline “Register” button that dispatches seva:open-registration; the modal listens and opens.
  • Custom button anywhere on the site: Your own button dispatches seva:open-registration with an eventSlug in the detail; the modal opens to that event.
  • Direct linking: Place the modal with the open attribute and an event-slug to auto-open on page load (e.g. for an “RSVP now” link from an email).

This is a modal component — auth is read from localStorage by the inner <seva-event-register>, so no glue script is required to propagate tokens. See Inline vs. modal components for details on the distinction.

The modal closes itself automatically when the registration flow advances to a state the modal shouldn’t keep blocking: a successful add-to-cart, a checkout starting, or the user declining the event.

The modal alone, opened from a custom button:

<script
type="module"
src="YOUR_COMPONENTS_URL/seva-event-register-modal.js"
></script>
<seva-event-register-modal
tenant-slug="my-club"
api-url="https://api.seva.tools"
>
</seva-event-register-modal>
<button
onclick="document.dispatchEvent(new CustomEvent('seva:open-registration', {
detail: { eventSlug: 'annual-gala' }
}))"
>
RSVP for Annual Gala
</button>

The <seva-event-register-modal> element must be present in the DOM for the event to be received — Lit components don’t auto-mount on event dispatch. The modal is rendered into a portal at document.body, so it can sit anywhere in your markup without affecting layout.

AttributeTypeDefaultDescription
event-slugstring''Initial event slug. Can be overridden at open time via the eventSlug field in the seva:open-registration event detail.
tenant-slugstring''Required. Your organization’s tenant slug.
api-urlstring'https://api.seva.tools'Base URL of the Seva API.
theme'light' | 'dark''light'Color theme passed through to the inner form.
auth-tokenstring | nullnullPre-supplied bearer token. When set, bypasses the inner form’s localStorage lookup. Rarely needed.
start-viewEventRegisterView'sign-in'Initial view inside the modal. Default skips 'event-info' because Webflow renders event details on the page already. Can be overridden at open time via the view field in the event detail.
openpresent/absentabsentIf present at mount, the modal auto-opens via queueMicrotask. Useful for deep-link / launched-from-URL flows. The Webflow CTA pattern uses event dispatch instead.

All events are observed on document:

EventDetailEffect
seva:open-registration{ eventSlug?, view? }Opens the modal. If eventSlug is provided and differs from the current value, updates it. The view field overrides start-view for this open; absent → resets to default.
seva:add-to-cart(any)Closes the modal. The cart drawer takes over.
seva:open-cart(any)Closes the modal so the cart drawer isn’t stacked behind it.
seva:checkout-started(any)Closes the modal — the cart drawer’s checkout flow has begun.
seva:registration-declined(any)Closes the modal after a decline action completes.

The modal does not dispatch any custom events of its own. The events you’ll observe (seva:add-to-cart, seva:registration-completed, seva:authenticated, etc.) are dispatched by the inner <seva-event-register> form.

The modal extends an internal PortalHost base class, which provides:

MethodDescription
show()Open the modal. Idempotent — safe to call when already open.
hide()Close the modal.

In normal use you should not need to call these directly — dispatch seva:open-registration instead, which lets multiple modals on the same page (e.g. across iframes or page-controllers) coordinate via the shared event channel.

  • The modal must be in the DOM at the time the open event fires. Lit components don’t bootstrap themselves on event dispatch; if the element is added to the DOM after a button click, the open won’t happen. Place <seva-event-register-modal> once, near the end of <body>, and leave it mounted.
  • The inner form remounts on each open. When the modal opens, it conditionally renders <seva-event-register> with the current event-slug and start-view. When it closes, the form is destroyed. This keeps state from one registration session from bleeding into the next.
  • start-view defaults to 'sign-in' rather than the form’s own default of 'event-info'. The reason: a Webflow event page already shows the event title, dates, and description above the CTA — duplicating them inside the modal would be redundant. Override via the view field in seva:open-registration if you do want to start at the event-info view.
  • The backdrop click closes the modal. A close button (×) in the top-right corner does the same. The close button is auto-focused when the modal opens for keyboard accessibility.
  • auth-token attribute is rarely needed. The inner form looks up the token from localStorage (seva-auth-{tenantSlug}) automatically. Only set this attribute when you have a token from outside the normal sign-in flow (e.g. a server-rendered page that mints a token server-side).
  • <seva-event-register-cta> — the recommended companion on event detail pages. The CTA renders the inline “Register” button and dispatches seva:open-registration.
  • <seva-event-register> — the form that the modal wraps. You don’t embed this directly when using the modal.
  • <seva-cart> / <seva-cart-drawer> — the drawer auto-opens on seva:add-to-cart (the same event that closes this modal), so the modal → drawer handoff is seamless.

A standalone “RSVP” button anywhere on the site, opening the modal directly:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Events — My Club</title>
<script
type="module"
src="YOUR_COMPONENTS_URL/seva-event-register-modal.js"
></script>
<script
type="module"
src="YOUR_COMPONENTS_URL/seva-cart-drawer.js"
></script>
</head>
<body>
<h1>Upcoming Events</h1>
<ul>
<li>
Annual Gala —
<button
onclick="document.dispatchEvent(new CustomEvent('seva:open-registration', {
detail: { eventSlug: 'annual-gala' }
}))"
>
RSVP
</button>
</li>
<li>
Summer Picnic —
<button
onclick="document.dispatchEvent(new CustomEvent('seva:open-registration', {
detail: { eventSlug: 'summer-picnic' }
}))"
>
RSVP
</button>
</li>
</ul>
<!-- One modal handles all events; eventSlug is set per-open via the dispatch detail. -->
<seva-event-register-modal
tenant-slug="my-club"
api-url="https://api.seva.tools"
>
</seva-event-register-modal>
<!-- Cart drawer handles checkout after add-to-cart. -->
<seva-cart-drawer tenant-slug="my-club" api-url="https://api.seva.tools">
</seva-cart-drawer>
</body>
</html>

For the recommended Webflow event-page pattern (CTA + modal), see <seva-event-register-cta>.