Components
ElvixProvider

ElvixProvider

Top-level context. Fetches the brand chord, factor config, and copy from elvix; pipes session state and the event channel to every nested <Elvix*> component.

Provider scope

Every nested elvix component reads brand + envelope from this provider. No prop drilling.

app/layout.tsx
import { ElvixProvider } from "@elvix.is/sdk/react";
import "@elvix.is/sdk/styles.css"; // REQUIRED. Without it every <Elvix*> surface renders unstyled.
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html>
<body>
<ElvixProvider clientId={process.env.NEXT_PUBLIC_ELVIX_CLIENT_ID!}>
{children}
</ElvixProvider>
</body>
</html>
);
}

Props

PropTypeRequiredDefaultDescription
clientIdstringrequiredn/aYour Application's client ID. Get it from Console, your Application, Credentials. Source from NEXT_PUBLIC_ELVIX_CLIENT_ID so client-side bundles can read it.
localestringoptional"en"BCP-47 locale tag ("en", "de", "pt-BR", "uk"). Flips every nested <Elvix*> component to the matching translation. Fifteen catalogs ship: en, de, es, fr, it, nl, pt-BR, pt-PT, tr, pl, cs, sv, el, ru, uk. English is bundled; the other fourteen lazy-fetch from i18nBase.
i18nBasestringoptional"https://elvix.is/api/v1/i18n/elvix"Override the translation CDN. Useful only when self-hosting translations off a different bucket.
baseUrlstringoptional"https://elvix.is"Override the elvix origin. Set this only for self-hosted instances or dev mirrors (e.g. https://elvix.edvone.dev).
childrenReact.ReactNoderequiredn/aYour app tree. The provider must wrap every <Elvix*> component and every hook (useUserRoles, useElvixApp, etc.).

clientId should come from NEXT_PUBLIC_ELVIX_CLIENT_ID. It is not a secret: Console-issued client IDs are safe to ship in client bundles. The provider uses it only to fetch the public brand and method bootstrap. Server-side verification still needs the user's session token.

Always import @elvix.is/sdk/styles.css alongside the provider. The SDK ships a single Tailwind-built stylesheet; without it every <Elvix*> surface renders unstyled (text-only, no brand chord, no card chrome).

The signed-in user: useElvixAppContext

useElvixAppContext() is the signed-in user's envelope for this app, or null while loading or signed out (useElvixSession() tells those apart). Read display values from it instead of fetching them yourself.

FieldTypeNotes
user.idstringThe elvix user id.
user.namestring | nullDisplay name, derived by elvix from given + family name.
user.emailstring | null
user.givenName, user.familyNamestring | nullIdentity summary (0.12+).
user.pronounsPronouns | null"she_her" | "he_him" | "they_them" | "other" | "prefer_not_to_say" (0.12+).
user.languages{ code: string; level: LanguageLevel }[]In the order ElvixLanguages lists them (0.12+).
membership.usernamestring | nullThe per-app handle.
membership.statusstringMembership lifecycle.
The 0.12 fields are optional in the type; an older elvix returns undefined. For the photo use useElvixUserMedia() (see Avatar): membership.avatarSizes is per-app and empty since photos were centralized.

useElvixContext().refresh() (or useElvixRefresh()) re-reads the envelope without flashing a signed-out state. Every SDK editor (ElvixUsername, ElvixIdentityForm, ElvixAvatar, ElvixBanner, ElvixLanguages) calls it after a save, so a new name, handle, photo or language reaches every consumer with no reload. Call it yourself only after changing the user through your own backend. Since SDK 0.12.

Birthdate and gender are deliberately NOT in the envelope: it reaches every allowed origin of every app the user signs into. ElvixIdentityForm reads them itself.

Brand

The brand chord comes from the brand prop, else the app's Console brand (brandColor / brandColorDark with their onBrandColor*), else elvix lavender. ElvixSignInButton and ElvixSignInForm use the same source for the theme they render in, so a host never restates colours elvix already holds. A light/dark theme pinned on the provider also sets the sign-in form's theme over the Console default.

Switching languages

Set locale to any of the fifteen production tags. Every nested <Elvix*> component switches to the matching catalog on the next render. The English catalog is bundled inside the SDK so the first paint is always instant; the other fourteen are fetched once per page from i18nBase and cached for the page lifetime.

app/layout.tsx (German UI)
<ElvixProvider
clientId={process.env.NEXT_PUBLIC_ELVIX_CLIENT_ID!}
locale="de"
>
{children}
</ElvixProvider>

Missing translations gracefully fall back to English (the bundled catalog is the fallback chain root). The copy prop on <ElvixSignIn> still wins over locale catalogs for per-embed overrides.

Self-hosting and dev mirrors

Default: the provider talks to https://elvix.is. Override baseUrl only when pointing at a self-hosted instance or a dev mirror. Most apps never set this prop.

app/layout.tsx (self-hosted)
<ElvixProvider
clientId={process.env.NEXT_PUBLIC_ELVIX_CLIENT_ID!}
baseUrl={process.env.NEXT_PUBLIC_ELVIX_BASE_URL} // e.g. https://elvix.edvone.dev
>
{children}
</ElvixProvider>

Disabling animations (0.7.12+)

Pass animated={false} on the provider to turn off mount + transition animations across EVERY nested <Elvix*> component in one move — <ElvixCard>'s brand trace, <ElvixSignInForm>'s step transitions, <ElvixDeactivate> / <ElvixLeave> / <ElvixAddressBook> / <ElvixSessions> / <ElvixExport> and the rest. Implemented via framer-motion's MotionConfig reducedMotion="always", so the cascade reaches every animation in the tree at zero per-component cost.

When animated is left at its default true, the provider broadcasts reducedMotion="user" instead — the SDK respects the browser's prefers-reduced-motion media query out of the box. Hosts get an accessibility-aware SDK by default and a hard kill-switch when they need it.

Use cases: screenshot / print surfaces, server-rendered emails, embedded checkouts, end-to-end tests where animation timing breaks assertions, and any UX research surface where motion noise muddies the read. Per-component animated props (e.g. <ElvixCard animated>) still override the cascade for one-off exceptions.

app/layout.tsx
import { ElvixProvider } from "@elvix.is/sdk/react";
// Disable every SDK animation everywhere inside this tree.
<ElvixProvider clientId="your-app" animated={false}>
{children}
</ElvixProvider>

Reading the cascade from your own components

If you build custom surfaces that compose <Elvix*> and want them to honor the same flag, call useElvixAnimated() — returns true outside a provider (so the hook is safe to call unconditionally) and the provider's resolved value inside one. Compose with a local override the same way the SDK does:

components/your-pane.tsx
import { useElvixAnimated } from "@elvix.is/sdk/react";
function YourPane({ animated: animatedProp }: { animated?: boolean }) {
const providerAnimated = useElvixAnimated();
const animated = animatedProp ?? providerAnimated;
// ... use `animated` to gate framer-motion initial/animate/transition
}

Related