ElvixSignInForm
The full branded sign-in surface (card, header, brand wash, every Console-enabled method, Secured-by-elvix badge). Exported as both `ElvixSignInForm` and the short alias `ElvixSignIn` — same component.
"use client";import { ElvixSignInForm } from "@elvix.is/sdk/react";import { useRouter } from "next/navigation";export default function SignInPage() {const router = useRouter();return (<ElvixSignInFormclientId={process.env.NEXT_PUBLIC_ELVIX_CLIENT_ID!}onResult={(r) => {if (!r.ok) return console.warn(r.error, r.message);if (r.token) {const secure = location.protocol === "https:" ? "; secure" : "";document.cookie = `elvix_token=${r.token}; path=/; samesite=lax${secure}`;}router.push(r.redirect ?? "/app");}}/>);}
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
clientId | string | optional | from <ElvixProvider> | Application client_id. Picked up from context when omitted. |
mode | "interactive" | "preview" | optional | "interactive" | preview paints every CTA without hitting auth endpoints. Console live-preview uses this. |
intent | "app" | "console" | optional | "app" | Routes auth requests for the host context. |
appName | string | optional | Console-configured | App display name. Explicit prop wins over the bootstrap envelope. |
logoUrl | string | null | optional | Console-configured | Logo URL. logoUrlDark overrides in dark theme. logoNode (ReactNode) wins over both. |
brandColor | string | optional | Console-configured | Primary brand color for CTAs. onBrandColor sets foreground painted on top. |
methodGoogle | boolean | optional | Console-configured | Toggle the Google factor. Same for methodEmailOtp, methodPasskey, methodUsername. |
googleConfig | { oneTap?, autoSelect?, popup?, fedcm?, hostedDomain? } | optional | none | Per-app Google Identity Services config. Falls back to redirect-OAuth when GIS is unavailable. |
googleClientId | string | optional | from bootstrap | Public Google OAuth client id for the GIS personalized button. |
layout | "centered" | "split" | "stacked" | optional | "centered" | Visual layout variant. |
socialLayout | "stacked" | "grid" | optional | "stacked" | Social button arrangement. |
presentation | "card" | "drawer" | "modal" | optional | "card" | Surrounding chrome. card renders the form inline. modal / drawer render an auto-trigger button that opens the form in an overlay and auto-closes on success. Console can preset this via the app's presentation setting. |
trigger | (open: () => void) => React.ReactNode | optional | a <ElvixSignInButton> | Render-prop for the overlay trigger (modal / drawer only). Receives open; return your own element to launch the overlay. |
triggerLabel | string | optional | the sign-in heading | Label for the default trigger button (modal / drawer only). |
triggerProps | Partial<ElvixSignInButtonProps> | optional | none | Full <ElvixSignInButton> surface (variant / size / shape / brandColor …) for the default trigger. |
open | boolean | optional | uncontrolled | Controlled overlay open state. Pair with onOpenChange. |
defaultOpen | boolean | optional | false | Initial open state when uncontrolled. |
onOpenChange | (open: boolean) => void | optional | none | Fires whenever the overlay opens or closes. |
drawerSide | "bottom" | "left" | "right" | optional | "bottom" | Which edge the drawer presentation slides in from (uses vaul). |
dismissable | boolean | optional | true | Whether backdrop-click / Escape (modal) or drag / backdrop (drawer) closes the overlay. |
width | number | string | optional | 420 | Overlay panel / drawer-sheet width. Pin to your container width so a bottom drawer fills it edge-to-edge. |
theme | "light" | "dark" | "auto" | optional | "light" | Theme override for the form's surface tokens. auto inherits from host. |
signInVerb | "signin" | "login" | optional | "signin" | CTA verb. SaaS defaults to "Sign in"; banks/B2B legacy prefer "Log in". |
showHeader | boolean | optional | true | Hide the built-in header (logo + heading + subtitle). |
framed | boolean | optional | true | Render the card frame. Set transparentBg to strip bg + border + shadow. |
transparentBg | boolean | optional | false | Strip card bg + border + shadow so the form blends into its host. |
belowHeading | React.ReactNode | optional | none | Slot rendered under the subtitle. For gate-state badges ("Private beta"). |
belowMethods | React.ReactNode | optional | none | Slot rendered under the methods, above the "Secured by elvix" chip. |
websiteUrl | string | null | optional | Console-configured | If set, logo becomes a link to this URL. |
privacyPolicyUrl | string | null | optional | Console-configured | Footer privacy link. termsOfServiceUrl covers ToS. |
redirectAfterSignIn | string | optional | backend value, then "/" | Single declarative fallback honoured by EVERY success path (OTP, Google, passkey, onboarding). |
onAuthenticated | (r: { ok: true; redirect?: string; token?: string }) => void | optional | none | Fires BEFORE the default redirect on success. When set, the form will NOT navigate; the host owns post-auth routing. |
onResult | (r: ElvixSignInResult) => void | optional | none | Terminal callback for every outcome (success + every error path). Branch on r.ok. |
ElvixSignIn is a re-export of ElvixSignInForm — same component, shorter name. Import whichever reads better; there is no longer a separate lower-level component.
Open the form in an overlay instead of inline with presentation="modal" or presentation="drawer". The SDK auto-renders a trigger button (<ElvixSignInForm presentation="modal" triggerLabel="Sign in" />); customise it with triggerProps (full <ElvixSignInButton> surface) or replace it entirely with the trigger render-prop. The overlay closes on success, on backdrop-click / Escape (modal), or drag / backdrop (drawer) unless dismissable={false}. The drawer uses vaul (the same primitive shadcn/ui Drawer wraps), so it drops into a shadcn host unchanged. Pin width to your container so a bottom drawer fills it edge-to-edge.
onAuthenticated suppresses the default redirect; onResult does not. If you set onAuthenticated, the host owns navigation. onResult fires on every outcome regardless, including errors.
After a Google round-trip (#elvix_token=... in the URL fragment), the form fires onResult AND onAuthenticated with the same { ok: true, token, redirect } payload that an in-frame OTP / passkey success carries. Your handler runs unchanged. Pin `^0.7.6`: 0.7.5 only fired onResult on the return path, so hosts wired to onAuthenticated (server-action token exchange before navigating) sat on /sign-in after Google instead of advancing.
Authenticating pane (0.7.12+). Between OTP / passkey verification and the host's onResult callback firing, the form switches to a dedicated step="authenticating" state rendering a Loader2 + Signing you in… + Hold on a second, taking you to <appName> line. Removes the stale-form half-second between the last keypress and the host's redirect.
Onboarding resume after Google return (0.7.12+). When elvix's Google callback encodes a remaining onboarding gate in the URL fragment as #elvix_landing=<base64-json>, the form drains it on mount and renders the username / passkey / recover gate inline. Hosts that don't mount the form on the return page get the legacy behaviour — token in fragment, host navigates to wherever it had planned. Both paths are backwards-compatible.
Try-inline-first passkey (0.7.12+). Cross-origin hosts now run navigator.credentials.get() inline FIRST (browsers honour elvix's /.well-known/webauthn Related Origin Requests manifest). If the browser still rejects with rp.id / SecurityError (older Firefox, older Safari), the form falls back to the hosted ceremony page on elvix.is via the redirect-OAuth pattern. Best UX for modern browsers, no regression for older ones.
Related
ElvixSignInButton
Drop-in 'Sign in with elvix' button. Four variants by three sizes by four shapes. The cheapest entry point: one line and you have a working sign-in flow.
ReadElvixSignOutButton
Symmetric counterpart of `<ElvixSignInButton>`. One click invalidates the elvix session server-side, clears the SDK's local token, drops the `elvix_token` cookie, then navigates.
Read