Username
better-auth-ui/usernameFreeComponent
Username plugin: username-based sign-in form and availability checking field. Registers a sign-in view that accepts both username and email, and a username field with real-time availability checking rendered on the sign-up form.
Live preview
live · rendered by the registry
Rendered by better-auth-ui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://better-auth-ui.com/r/username.jsonSource
1"use client"23import {4 type UsernameAuthClient,5 useAuth,6 useAuthPlugin,7 useIsUsernameAvailable8} from "@better-auth-ui/react"9import { useDebouncer } from "@tanstack/react-pacer"10import { Check, X } from "lucide-react"11import { useState } from "react"12import type { AdditionalFieldProps } from "@/components/auth/additional-field"13import { Field, FieldError, FieldLabel } from "@/components/ui/field"14import {15 InputGroup,16 InputGroupAddon,17 InputGroupInput18} from "@/components/ui/input-group"19import { Spinner } from "@/components/ui/spinner"20import { usernamePlugin } from "@/lib/auth/username-plugin"2122/**23 * Renderer for the `username` additional field. Owns availability checking,24 * length limits, and visual indicators. `isInvalid` reflects only browser25 * validation (minLength, required, etc.) — availability feedback is shown26 * via the icon and `aria-label` without affecting the field's invalid state.27 */28export function UsernameField({29 name,30 field,31 isPending32}: AdditionalFieldProps) {33 const { authClient, localization: authLocalization } = useAuth()34 const {35 localization,36 minUsernameLength,37 maxUsernameLength,38 isUsernameAvailable: checkAvailability,39 usernamePrefix40 } = useAuthPlugin(usernamePlugin)4142 const currentUsername = String(field.defaultValue ?? "")43 const [value, setValue] = useState(currentUsername)44 const [error, setError] = useState<string>()4546 const {47 mutate: requestAvailability,48 data: availability,49 error: availabilityError,50 reset: resetAvailability51 } = useIsUsernameAvailable(authClient as UsernameAuthClient, {52 onError: () => {}53 })5455 const debouncer = useDebouncer(56 (next: string) => {57 const trimmed = next.trim()58 if (!trimmed || trimmed === currentUsername) {59 resetAvailability()60 return61 }6263 requestAvailability({ username: trimmed })64 },65 { wait: 500 }66 )6768 function handleChange(next: string) {69 setValue(next)70 setError(undefined)71 resetAvailability()7273 if (checkAvailability) {74 debouncer.maybeExecute(next)75 }76 }7778 const isCheckingAvailability =79 !!checkAvailability && !!value.trim() && value.trim() !== currentUsername8081 return (82 <Field data-invalid={!!error}>83 <FieldLabel htmlFor={name}>{field.label}</FieldLabel>8485 <InputGroup>86 {usernamePrefix && (87 <InputGroupAddon align="inline-start">88 {usernamePrefix}89 </InputGroupAddon>90 )}9192// … truncated
What it pulls in
npm packages
Other registry items
Files it writes
More from better-auth-ui
All 49 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Account Settingsaccount-settings | better-auth-ui | Components | Free | 2 deps | |
| Active Sessionsactive-sessions | better-auth-ui | Components | Free | 5 deps · 2 files | |
| Additional Fieldadditional-field | better-auth-ui | Components | Free | 5 deps | |
| Adminadmin | better-auth-ui | Components | Free | 4 deps · 3 files | |
| Anonymousanonymous | better-auth-ui | Components | Free | 4 deps · 3 files | |
| API Keyapi-key | better-auth-ui | Components | Free | 4 deps · 10 files | |
| Authauth | better-auth-ui | Components | Free | 2 deps | |
| Auth Providerauth-provider | better-auth-ui | Components | Free | 4 deps · 2 files |
