Full-height username picker with a prefixed input group, a live availability indicator, suggestion chips when a handle is taken, and a submit button that unlocks only when the name is free. Perfect for onboarding handle selection.
Full-height username picker: a bordered card with a URL-prefixed input group, a live taken/available indicator with icon and colored helper text, suggestion chips that appear when the typed handle is taken, and a submit button that only unlocks once the name is free. Built for onboarding handle selection.
Pro blocks install through the shadcn CLI with your license key and ship their full source. Docs and live previews stay open to everyone, so you can read every block's details first.
Swap YOUR_EMAIL and YOUR_KEY for the email and license key on your account. Find your license key on your account page.
Radix flavor
npx shadcn add "https://ui.beste.co/r/auth25?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
npx shadcn add "https://ui.beste.co/r-base/auth25?email=YOUR_EMAIL&license_key=YOUR_KEY"This installs the block to components/beste/block/auth25.tsx and the button, input-group, and field shadcn/ui primitives it's built on.
The installed file exports auth25Demo alongside the block: the exact props behind the preview above. Spread it to get a working username picker in one line.
import { Auth25, auth25Demo } from "@/components/beste/block/auth25";
export default function ClaimUsernamePage() {
return <Auth25 {...auth25Demo} />;
}Then replace the demo with your own props. Written out, a trimmed setup looks like this:
import { AtSign } from "lucide-react";
import { Auth25 } from "@/components/beste/block/auth25";
export default function ClaimUsernamePage() {
return (
<Auth25
icon={<AtSign className="size-7" />}
heading="Claim your username"
description="This is how others will find you."
takenUsernames={["jane", "admin", "team"]}
suggestions={["jane_co", "janecooper"]}
labels={{
field: "Username",
urlPrefix: "beste.co/",
available: "{username} is available",
taken: "{username} is already taken",
submit: "Claim username",
}}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
icon | React.ReactNode | – | Icon rendered in a muted circle above the heading |
heading | string | – | Screen title |
description | string | – | Subtext below the heading |
takenUsernames | string[] | [] | Handles checked against the typed input to flag it as taken |
suggestions | string[] | [] | Chips offered when the typed handle is taken |
labels | object | {} | Field, status, and button copy, see below |
skipPrompt | { text: string; linkLabel: string; href: string } | – | Line below the card; hidden entirely when not set |
className | string | – | Extra classes for the outer <section> |
type Auth25Labels = {
field?: string;
urlPrefix?: string;
usernamePlaceholder?: string;
available?: string;
taken?: string;
suggestionsLabel?: string;
submit?: string;
};takenUsernames.includes(...). There is no debounce and no network call, so takenUsernames has to be a complete list passed in as a prop.labels.available or labels.taken) is a template string with the literal {username} token replaced by the trimmed (but not lowercased) input value, and its color follows the state: emerald for available, rose for taken, matching a Check/X icon inside the input group's trailing addon.suggestions is non-empty; clicking a chip calls setUsername(suggestion) to fill the input, but does not auto-submit, so the availability check still re-runs against takenUsernames for the new value (a suggestion isn't guaranteed available unless the caller keeps the two lists disjoint).disabled unless the input is non-empty and not in takenUsernames; the <form> itself only calls e.preventDefault(), so there is no wired network submission even once the button is enabled.urlPrefix (e.g. "beste.co/") renders as a static, non-editable addon segment ahead of the input via InputGroupAddon/InputGroupText, not as part of the input's own value.Wiring the form up
This block ships the form markup only; state, validation, and submit are yours to add. Our guide wires the shadcn Field primitives to React Hook Form, TanStack Form, and Formisch on one field system.
auth7
Full-height account picker that lists saved accounts with avatars, names, and emails, plus a use-another-account row. Perfect for multi-account apps, SSO hubs, and returning-user sign-in.
auth36
Full-height workspace picker listing organizations with logo initials, member details, and a create-workspace row, plus a signed-in-as footer. Perfect for multi-tenant apps after sign-in.
auth24
Full-height profile setup step with an avatar uploader, a display name field, and a bio textarea, plus a skip option. Perfect for the post-sign-up onboarding step where users personalize their account.
auth43
Full-height waitlist capture with an email field, a join button, a social-proof line, and a sign-in link for existing users. Perfect for pre-launch and early-access landing gates.
auth11
Full-height onboarding step where the user picks an account type from selectable radio cards with icons and descriptions, then continues. Perfect for tailoring sign-up flows by persona or plan.
auth8
Full-height re-authentication screen showing the signed-in user's avatar, name, and email with a single password field, a forgot-password link, and a use-a-different-account option. Perfect for session unlock and returning-user prompts.