RegisterPage
A registration form gated by an invitation token, with a live password-requirements checklist, posting to your register endpoint. Localizable through AuthLocale; restyle with snippet overrides or slotClasses.
01 Usage
Basic
<script lang="ts">
import { RegisterPage } from '@urbicon-ui/auth';
import { goto } from '$app/navigation';
import { page } from '$app/state';
import { resolve } from '$app/paths';
</script>
<!-- The invitation link is /auth/register?token=<secret>&email=<invitee>; the
token is the proof of invitation, so read both off the URL. -->
<RegisterPage
token={page.url.searchParams.get('token') ?? ''}
defaultEmail={page.url.searchParams.get('email') ?? ''}
onSuccess={() => goto(resolve('/'))}
/>
02 Accessibility
The requirements list has a name
The password checklist is a real <ul> carrying aria-label, and the password field points at it
with aria-describedby. The list is in the DOM from
the first paint, not from the first keystroke — a description attached to an
already-focused field is not reliably re-announced, so rules that appeared only after
typing would never be read at all.
A refused password says which rule
The submit button is never disabled for an unmet rule. Submitting a password that misses
one produces an error naming the rules it misses, so the reason is reachable even with showRequirements set to false. The server's refusal carries the same rules
as machine values plus the policy it measured against, so the message is localized and the
form re-gates on the real policy rather than repeating the refusal.
Pass/fail is text, not colour
Each requirement is prefixed with a literal ✓ or ✗ character, not an icon and not a colour swap
alone, so the state survives a monochrome display. The glyph carries role="img" with a translated accessible name
(“Met” / “Not met”), because a bare check mark is announced in the
reader’s language rather than the page’s. The data-met attribute mirrors it for CSS only. Note the
list is not itself a live region: it updates as you type but is not announced on every keystroke,
which would make the field unusable with speech output.
Mismatch is bound to the field
A confirm-password mismatch is passed to the field as the error prop, so Input sets aria-invalid and links the message through aria-describedby. The reader hears the problem
while focus is on the field that has it. Server-side failures go to the page-level live
region instead.
Autofill hints
autoComplete is set on all four fields — name, email,
and new-password on both password fields, which is the signal
a password manager needs to offer a generated password rather than the saved one.
03 API Reference
Prop | Type | Default | Description | |
|---|---|---|---|---|
token required | string | — | The invitation token from the ?token= query param. **Required to
register**: possession of it is the entire proof of invitation, so
without it the request is rejected before anything is looked up.
Read it in your route the same way as defaultEmail:
token={page.url.searchParams.get('token') ?? ''}.
It is a credential: keep it out of logs and analytics, and do not put it in
a page title or a shared screenshot.
Required rather than optional-with-a-default on purpose: a page rendered
without it can only ever produce a 400, and an optional prop makes that
mistake type-check. This way the compiler names every call site. | |
apiPath | string | '/api/auth/register' | API endpoint for the register request. | |
class | string | — | Extra classes on the root element. | |
csrf | CsrfClientOptions | — | CSRF cookie/header names, needed only when the server overrides the defaults via config.csrf. Mutating requests echo the token automatically. | |
defaultEmail | string | '' | Pre-fills the email field. Pass the ?email= query param from the
invitation link (createInvitationHandlers builds
/auth/register?token=<secret>&email=<invitee>) so an invited user lands on
a ready-to-submit form instead of retyping. Following the same explicit-prop
pattern as ResetPasswordPage/VerifyEmailPage's token, read it from the
page in your route (SSR-safe), e.g.
defaultEmail={page.url.searchParams.get('email') ?? ''}.
Convenience only — the invitation names its own address, and registering
with a different one is refused. | |
fetcher | typeof globalThis.fetch | — | Custom fetch implementation for all API calls. Defaults to the global fetch. Useful for mock backends in demos/tests or custom retry/auth layers. | |
footer | Snippet | — | Content rendered below the form, above links (e.g. terms checkbox). | |
header | Snippet | — | Content rendered above the form (e.g. social login buttons). | |
links | Snippet | — | Replaces the link area. | |
loginUrl | string | '/auth/login' | URL for the login page link. | |
onSuccess | () => void | — | Called after successful registration. | |
passwordPolicy | PasswordPolicy | — | The password policy to gate against, when you already have it server-side
(resolvePasswordPolicy(config.password) in a +page.server.ts load).
Supplying it skips the policyPath request — useful for SSR, and the only
way to gate correctly when the endpoint is not mounted. | |
policyPath | string | null | '/api/auth/password-policy' | Endpoint serving createPasswordPolicyHandler, read once on mount so the
checklist and the submit gate match what the server enforces. null
disables the request and falls back to the package defaults (min 8, no
character classes). | |
preset | string | — | Apply a named preset registered via <BlocksProvider presets={{ RegisterPage: { … } }}>.
Resolves after the provider defaults and before this instance's own
slotClasses, so a project-wide look lives in one place instead of being
repeated at every usage site. | |
showRequirements | boolean | true | Show real-time password requirements checklist. | |
slotClasses | AuthPageSlotClasses | — | Per-slot class overrides. Keys: root, card, title, form, field, submit, error, success, links. | |
t | PartialAuthLocale | — | Locale overrides, deep-merged over the bundle registered for the active
locale — English unless registerAuthLocale ran for it. Pass any subset,
from a single string to a whole tree. | |
unstyled | boolean | — | Strip all default styling. |
04 Types
Local type definitions used by this component.
Name | Kind | Category | Used by | Description | |
|---|---|---|---|---|---|
RegisterPageProps | interface | props | 0 | — | |
PartialAuthLocale | type | helper | 1 | Consumer-facing locale input: any subset of AuthLocale. Components
accept this as their t prop and deep-merge it over the bundle registered
for the active locale — English unless registerAuthLocale ran for it — so
overriding a single string never silently blanks the rest. | |
PasswordPolicy | interface | helper | 1 | The password policy in force, with every default already applied — what
validatePasswordStrength measures a password against, and what
createPasswordPolicyHandler ships to the browser so the client-side gate
cannot disagree with the server.
Deliberately NOT PasswordConfig: that type also carries
pbkdf2Iterations, a hashing work factor that is nobody's business on the
wire. This shape is the projection, and it is the only thing the endpoint
serializes. | |
CsrfClientOptions | interface | helper | 1 | — | |
AuthPageSlotClasses | interface | helper | 1 | Per-slot CSS class overrides for auth page components (LoginPage, RegisterPage, etc.). Each key targets a specific visual area of the page. Only the slots you override are affected. | |
DeepPartial | type | helper | 0 | Recursive partial: every branch and leaf becomes optional. | |
AuthLocale | interface | helper | 0 | The complete auth locale bundle. Every key is required: the bundles this
package ships (en, de) satisfy the full shape, and consumer overrides
enter as PartialAuthLocale, deep-merged by mergeAuthLocale over the
bundle registered for the active locale — English unless registerAuthLocale
ran for it — so component markup reads keys directly, without per-key
?? '…' fallback literals.
Placeholder convention: dynamic values use **single-brace** tokens
({n}, {name}, {email}) that the consuming component substitutes itself
via String.replace('{token}', value). There is deliberately **no**
{{…}} runtime interpolator in this package. The key-based translator twin
(authT/at) was removed, so {{…}} here would render verbatim. |
05 Installation
Import
import { RegisterPage } from '@urbicon-ui/auth';