Skip to content

Components · Identity

UsernameAvailabilityInput

Input with an injected, debounced async check, a status icon and an announced result.

@rookcom/monarch-reactComponent

Workspace address

example.com/

Try “team” to see a taken address.

Submit enabled: no

Usage examples

Settled states

Purpose

A text input whose value is checked while the user types, such as a handle, workspace address or slug. The product supplies the check; the component debounces it, drops stale answers, shows the status and announces the result.

Use when

  • A value must be unique or otherwise approved by a server before the form can be sent.
  • The user benefits from knowing the answer before submitting (handles, addresses, slugs).

Avoid when

  • Validation is purely local: use Input with FieldError.
  • The check is expensive or rate-limited per keystroke: validate on submit instead.

Design principles

  • Generic by design: the product passes validate, so restricted names and lookups stay in the product.
  • Status is never colour alone: every state has an icon and a text message.
  • Only settled results are announced; "checking" is shown, not spoken on every pause.
  • The latest value always wins: earlier checks are aborted and their late answers ignored.

API reference

import { UsernameAvailabilityInput, useAsyncValidation } from '@rookcom/monarch-react';
ExportKindRenderingRoot class
UsernameAvailabilityInputcomponentclient.mn-username-availability-input
useAsyncValidationhookclient–

useAsyncValidation(value, validate, { debounce }) is the same logic as a hook, returning { status, message, revalidate }, for products that need it on another control.

The ref and native input props go to the <input>; className goes to the .mn-username-availability-input wrapper.

Generated from the TypeScript declarations of packages/react/src/components/identity/username-availability-input.

Properties

validate(value, signal) may return a result synchronously or as a promise. Return null for "nothing to check" (for example the user’s current handle); throw or reject for "could not check".

UsernameAvailabilityInput

A text input whose value is checked asynchronously while the user types: handles, workspace addresses, slugs. The product supplies the check; the component debounces it, aborts stale requests, shows a status icon with a text message, and announces the result to screen readers.

PropTypeDescription
validate requiredAsyncValidatorThe product's check: local rules and the availability lookup. Required.
childrenReactNode
classNamestringClass for the outer wrapper (the input itself is `.mn-username-availability-input__input`).
debouncenumberMilliseconds without typing before `validate` runs. Default 400.
defaultValuestringInitial text when uncontrolled.
disabledboolean
idstring
invalidbooleanMarks the value invalid regardless of the check. Inside a Field, the Field's `invalid` is used.
messagesPartial<UsernameAvailabilityInputMessages>Override the default status texts.
onStatusChange((status: AsyncValidationStatus, message: string | undefined) => void)Called whenever the status changes, so a form can block submit until `valid`.
onValueChange((value: string) => void)Called with the new text (after `transform`) on every change.
prefixReactNodeFixed text before the value, such as a domain ("example.com/"). Read as part of the description.
size"sm" | "md" | "lg"
transform((raw: string) => string)Rewrites typed text before it is stored, e.g. lower-casing or slugifying.
valuestringThe text (controlled).

Variants

PropValuesDescription
size'sm''md''lg'Control height from --mn-control-*, as for Input.

States

StateExposed asBehaviour
Idledata-status="idle"Empty, or the validator returned null. No icon or message.
Checkingdata-status="checking"Spinner and "Checking availability…" from the first keystroke until the answer arrives.
Validdata-status="valid"Check icon, success border and message (default "Available").
Invaliddata-status="invalid", aria-invalid="true"Warning icon, danger border and the validator’s message (default "Not available").
Errordata-status="error"The check failed: an info icon, a message and a "Try again" button that re-runs it at once.

Interaction behaviour

  • Each change applies transform, calls onValueChange, then runs validate after debounce ms without typing (default 400).
  • A new value aborts the previous check through its AbortSignal; a result that arrives late is ignored.
  • onStatusChange(status, message) fires on every status change, so the form can disable submit until valid.
  • Controlled with value + onValueChange, or uncontrolled with defaultValue.

Keyboard support

KeysAction
TabMoves to the input, then to "Try again" when a check has failed.

Typing and editing are the native input’s own; the component adds no key handling.

Accessibility

Role
textbox
Accessible name
A FieldLabel, or aria-label.
  • The prefix and the status message are linked with aria-describedby, so the full address and the result are read with the field.
  • Settled results are announced through a polite role="status" region that is always present.
  • aria-invalid is set while the value is unavailable or the Field is invalid.
  • Icons are aria-hidden; the text carries the meaning.
  • Autocorrect, autocapitalise and spellcheck are off, since handles are not words.

Responsive behaviour

  • Fills its container. A long prefix is truncated with an ellipsis at half the width, leaving room to type.
  • The message wraps under the field at narrow widths.

Theme support

  • Status colours are semantic tokens (--mn-color-success-*, --mn-color-danger-*, --mn-color-warning-strong), so light, dark and more-contrast themes apply.
  • The spinner slows under prefers-reduced-motion (Spinner’s own rule).

Do and don't

Do

  • Pass the AbortSignal to fetch so abandoned checks stop.
  • Return null for the user’s current value, so editing a profile does not report their own handle as taken.
  • Keep submit disabled until the status is valid, and re-check on the server when the form is sent.

Don't

  • Do not put restricted-name lists or uniqueness rules in Monarch; they belong in validate.
  • Do not set debounce to 0 for a server check; it sends a request per keystroke.
  • Input: Plain Input when there is no asynchronous check.
  • Field: Label, help and error wiring around it.
  • Spinner: The checking indicator.

Dependencies

KindDepends on
npm packagesreact
Monarch componentsField, Spinner

Uses the .mn-input styles from text-field for the control.

Testing coverage

  • Debounces the check, shows "checking" without announcing it, then announces and describes the result.
  • Marks unavailable values invalid with the default or the validator’s message.
  • Aborts stale checks; a late answer never overwrites the latest one.
  • A failed check shows an error and "Try again" re-runs it.
  • Empty values and null results are idle; onStatusChange reports each change.
  • transform rewrites the value in controlled mode.
  • The prefix and Field description are part of the accessible description.
CheckCovered
Axe in jsdomYes
Server renderingYes
Browser suitesVisual baselines: /__gallery; Cross-browser axe: /components/username-availability-input

Tests: packages/react/src/components/identity/username-availability-input