Better Auth UI for Svelte 5
better-auth-ui-svelte provides pre-built, customizable authentication UI components designed specifically for integration with the Better Auth backend in Svelte 5 applications. Currently at version 0.12.4, this library is in active early stage development, cautioning users that it is not yet battle-tested in production environments and issues may arise before a v1.0 stable release. The package aims for a rapid iteration cycle, with minor and patch releases occurring frequently as seen in its recent history (multiple patch and minor releases within months). A key differentiator is its full feature parity with the original Better Auth UI React library, leveraging Svelte 5 runes and modern practices, while also introducing Svelte-specific utilities like path helpers. It is styled with Tailwind CSS v4 and built upon shadcn-svelte components, offering extensive customization options out-of-the-box. The library supports Zod 4 for form validation and is localization-ready, but users should be aware that this Svelte port may diverge from the React version's API and features over time.
Common errors
-
Failed to resolve import "better-auth-ui-svelte/css" from "<your-css-file>"
cause Incorrect path or missing CSS file for TailwindCSS v4 import.fixEnsure your `better-auth-ui-svelte` package is correctly installed and that the `@import 'better-auth-ui-svelte/css';` statement is in a CSS file processed by TailwindCSS. -
Error: Hydration completed but contains mismatches.
cause Client-side rendering output does not match server-side rendering output, often due to dynamic content or environmental differences during SSR.fixCheck for components that render differently based on client-side state or environment variables. Ensure consistent configuration between SSR and CSR, and consider using `onMount` for client-only rendering logic for non-critical elements. -
Error: hooks called inside $derived
cause Svelte 5 runes are misused, specifically calling reactive hooks (like those for data fetching or effects) within a `$derived` block.fixMove any side-effecting or hook-based logic out of `$derived` computations. `$derived` should only compute a value based on other reactive states, not perform actions. Use `$effect` for side effects. -
Infinite reactive loop detected in Svelte 5 form or effect.
cause A state update within an `$effect` or form handler is causing the effect or form to re-evaluate and update the state again, leading to an endless cycle.fixWrap state-setting calls within `$effect` blocks (e.g., `form.setFieldValue()`) in `untrack(() => { ... })` to prevent the update from re-triggering the effect itself. Carefully manage dependencies and side effects in Svelte 5 runes.
Warnings
- gotcha This library is in early stage development and has not been battle-tested in production environments. Issues may arise before v1.0 stable. Use at your own risk.
- breaking For TailwindCSS v4, the CSS import mechanism changed from content configuration to a direct `@import` statement in your global CSS. Older content configuration for v3 is deprecated.
- gotcha The Svelte port may evolve independently and diverge from the original React library's API and features over time, prioritizing the needs of the Svelte ecosystem and maintainer's projects.
- gotcha Changes in Svelte 5's reactivity model, specifically the use of `$derived` and `$effect` runes, can lead to infinite reactive loops or delayed data loading if not handled carefully, particularly with form fields or data fetching.
- breaking The `UserButton` component's structure was enhanced with a `menuItems` snippet prop, allowing callers to inject custom `DropdownMenu` items.
Install
-
npm install better-auth-ui-svelte -
yarn add better-auth-ui-svelte -
pnpm add better-auth-ui-svelte
Imports
- AuthLayout
const AuthLayout = require('better-auth-ui-svelte').AuthLayout;import { AuthLayout } from 'better-auth-ui-svelte'; - UserButton
import UserButton from 'better-auth-ui-svelte/UserButton.svelte';
import { UserButton } from 'better-auth-ui-svelte'; - nlLocalization
import { nlLocalization } from 'better-auth-ui-svelte/localization';import { nlLocalization } from 'better-auth-ui-svelte';
Quickstart
import { SvelteKitAuth } from 'better-auth/client';
import { AuthLayout, UserButton, ChangeEmailCard } from 'better-auth-ui-svelte';
// In src/lib/auth.ts (or similar)
export const auth = new SvelteKitAuth({
apiEndpoint: '/api/auth'
});
// In src/routes/+layout.svelte
<script lang="ts">
import { onMount } from 'svelte';
import '../app.css'; // Your global CSS with Tailwind imports
import { auth } from '$lib/auth';
onMount(() => {
// Initialize auth client if needed, or ensure stores are reactive
});
</script>
<AuthLayout>
<UserButton />
</AuthLayout>
<!-- In src/routes/settings/email/+page.svelte -->
<script lang="ts">
import { auth } from '$lib/auth';
</script>
<ChangeEmailCard auth={auth} />