Skip to content

UI Library

@authrim/sveltekit/ui provides 30+ pre-built Svelte components for building authentication UIs. All components are:

  • Themeable — CSS custom properties (--authrim-*)
  • Accessible — ARIA roles, focus management, keyboard navigation
  • Dark mode ready — Light/dark themes via [data-theme="dark"]
  • Zero dependencies — Pure Svelte, no external UI library required
import { Button, Input, Card, EmailCodeForm } from '@authrim/sveltekit/ui';
import '@authrim/sveltekit/ui/styles'; // Theme CSS
ComponentPropsDescription
Buttonvariant, size, loading, disabled, fullWidth, typePrimary action button with variants and loading spinner
Inputtype, size, value, placeholder, error, errorMessage, label, requiredText input with label, error state, and validation
Cardpadding, bordered, shadow, hoverableContainer with header/footer slots
Dialogopen, title, closeOnOverlay, closeOnEscapeModal dialog with focus trap and overlay
Badgevariant, dotStatus indicator with color variants
SpinnersizeLoading spinner animation
Alertvariant, title, dismissibleAlert message (success/error/warning/info)
LanguageSwitcherlocales, currentLocaleLanguage selection dropdown
CountdownTimerexpiresAt, size, showIcon, warnAt, criticalAtCountdown display
ComponentPropsDescription
AuthErrormessage, dismissibleError display with dismiss button and role="alert"
OTPInputlength, value, disabled, error, autoFocusSegmented code input with paste support and auto-advance
ResendCodeButtonremainingTime, text, loading, disabledResend button with countdown timer
ComponentPropsDescription
EmailCodeFormstep, email, maskedEmail, loading, error, resendRemainingTimeTwo-step email + code form
SocialLoginButtonsproviders, layout, loading, loadingProvider, compactProvider buttons with icons
PasskeyConditionalInputvalue, placeholder, disabled, size, label, showPasskeyHintUsername input with WebAuthn autofill affordance
UserCodeInputvalue, disabled, placeholder, label, hintDevice-flow user-code input
QRCodeDisplaydata, imageUrl, size, label, captionQR code display wrapper
ClientInfoclient, trustedLabel, privacyPolicyLabel, termsLabelOAuth client metadata display
ConsentScopesListscopes, labelMapOAuth scope display list
OrgSelectororganizations, selectedOrgId, label, primaryLabelConsent organization selector
CIBARequestCardrequest, loading, approveLabel, denyLabelSingle CIBA approval card
ComponentPropsDescription
PasskeyListpasskeys, loading, deletingIdList of registered passkeys with delete
PasskeyRegisterButtonloading, disabled, variant, size, fullWidthRegister new passkey button
PasskeyDeleteButtoncredentialId, loadingDelete passkey confirmation button
ComponentPropsDescription
SessionListsessions, currentSessionId, loading, revokingIdActive session list with revoke
SessionRevokeButtonsessionId, loadingRevoke session button
SessionExpiryIndicatorexpiresAtSession expiry indicator
ComponentPropsDescription
LinkedAccountsListaccounts, loadingLinked social accounts
LinkAccountButtonprovider, loadingLink new social account
UnlinkAccountButtonaccountId, provider, loadingUnlink social account
<script lang="ts">
import { Button } from '@authrim/sveltekit/ui';
</script>
<Button variant="primary" size="md" loading={false} onclick={handleClick}>
Sign In
</Button>
<Button variant="outline" fullWidth>
Continue with Email
</Button>
<Button variant="destructive" size="sm">
Delete Account
</Button>

Variants: primary, secondary, outline, ghost, destructive

Sizes: sm (34px), md (42px), lg (50px)

<script lang="ts">
import { Input } from '@authrim/sveltekit/ui';
let email = $state('');
</script>
<Input
type="email"
label="Email address"
placeholder="[email protected]"
bind:value={email}
required
error={!email.includes('@')}
errorMessage="Invalid email address"
/>
<script lang="ts">
import { OTPInput } from '@authrim/sveltekit/ui';
</script>
<OTPInput
length={6}
autoFocus
on:complete={(e) => verifyCode(e.detail.value)}
on:input={(e) => console.log('Current:', e.detail.value)}
/>

Features: Auto-advance between digits, paste support, arrow key navigation, shake animation on error.

<script lang="ts">
import { EmailCodeForm } from '@authrim/sveltekit/ui';
let step: 'email' | 'code' = $state('email');
let email = $state('');
let loading = $state(false);
</script>
<EmailCodeForm
{step}
{email}
{loading}
on:submit-email={(e) => sendCode(e.detail.email)}
on:submit-code={(e) => verifyCode(e.detail.code)}
on:back={() => { step = 'email'; }}
on:resend={() => resendCode()}
on:dismiss-error={() => { error = ''; }}
/>
<script lang="ts">
import { SocialLoginButtons } from '@authrim/sveltekit/ui';
</script>
<SocialLoginButtons
providers={['google', 'github', 'apple']}
layout="vertical"
on:click={(e) => auth.social.loginWithPopup(e.detail.provider)}
/>

Layouts: vertical (stacked), horizontal (row), grid (auto-fit)

Built-in icons: Google, Apple, Microsoft, GitHub, Facebook — each with branded colors.

<script lang="ts">
import { PasskeyList } from '@authrim/sveltekit/ui';
</script>
<PasskeyList
passkeys={[
{ credentialId: 'abc', name: 'MacBook Pro', deviceType: 'platform',
createdAt: new Date('2024-01-15'), lastUsedAt: new Date('2024-06-01') },
]}
on:delete={(e) => deletePasskey(e.detail.credentialId)}
/>
<script lang="ts">
import { SessionList } from '@authrim/sveltekit/ui';
</script>
<SessionList
sessions={[
{ sessionId: 'sess_1', browser: 'Chrome', os: 'macOS',
lastActiveAt: new Date(), isCurrent: true },
{ sessionId: 'sess_2', browser: 'Safari', os: 'iOS',
lastActiveAt: new Date('2024-05-20') },
]}
currentSessionId="sess_1"
on:revoke={(e) => revokeSession(e.detail.sessionId)}
/>

Override theme variables to change the look:

:root {
--authrim-color-primary: #0066cc;
--authrim-color-primary-hover: #0052a3;
--authrim-radius-md: 8px;
--authrim-font-sans: 'Inter', sans-serif;
}

Every component accepts a class prop:

<Button class="my-custom-button" variant="primary">
Submit
</Button>
<style>
:global(.my-custom-button) {
text-transform: uppercase;
letter-spacing: 0.05em;
}
</style>

Replace internal sections with slots:

<Card>
{#snippet header()}
<h2>Custom Header</h2>
{/snippet}
<p>Card body content</p>
{#snippet footer()}
<Button>Save</Button>
{/snippet}
</Card>

Import the theme CSS to get the default styling:

import '@authrim/sveltekit/ui/styles';
TokenLightDarkPurpose
--authrim-color-primary#4f46e5#818cf8Primary actions
--authrim-color-accent#f43f5e#fb7185Accent/highlight
--authrim-color-success#059669#34d399Success states
--authrim-color-warning#d97706#fbbf24Warning states
--authrim-color-error#e11d48#fb7185Error states
--authrim-color-info#0891b2#22d3eeInfo states
--authrim-color-bg#ffffff#09090bBackground
--authrim-color-text#09090b#fafafaText
--authrim-color-border#e4e4e7#27272aBorders
TokenValuePurpose
--authrim-radius-sm6pxSmall elements
--authrim-radius-md10pxButtons, inputs
--authrim-radius-lg14pxCards
--authrim-radius-xl20pxLarge containers
--authrim-shadow-smsubtleCards, inputs
--authrim-shadow-mdmoderateDialogs
--authrim-shadow-lgprominentDropdowns
TokenValue
--authrim-font-sans'DM Sans', system-ui, sans-serif
--authrim-font-mono'JetBrains Mono', monospace
--authrim-text-sm0.875rem
--authrim-text-base1rem
--authrim-text-lg1.125rem

Dark mode activates via [data-theme="dark"] or prefers-color-scheme: dark:

<!-- Manual toggle -->
<html data-theme="dark">
/* Auto-detection (default behavior) */
@media (prefers-color-scheme: dark) {
:root { /* dark tokens applied automatically */ }
}