User Flows

Form

Design the recovery forms so they feel calm, direct, and easy to complete. Albatroz works well with simple local state or with a form library such as React Hook Form.

In this section

Follow the same recovery flow across installation, forms, auth, API wiring, and email delivery.

Structure

Keep the existing docs routes, but present them in a cleaner shell that matches the rest of the product UI.

Forgot-password request form

The recovery request screen should only ask for the user email, validate it quickly, and submit without friction. This keeps the experience clear at the exact moment a user is already under stress.

React Hook Form example

import React from 'react';
import { useForm } from 'react-hook-form';
import { useForgotPassword } from 'albatroz';

export default function ForgotPasswordScreen() {
  const { loading, submitHandler } = useForgotPassword();
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm();

  return (
    <form onSubmit={handleSubmit(submitHandler)}>
      <label htmlFor="email">Email</label>
      <input
        id="email"
        type="email"
        placeholder="name@company.com"
        {...register('email', {
          required: 'Please enter a valid email',
          pattern: {
            value: /^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$/i,
            message: 'Please use a valid email format',
          },
        })}
      />
      {errors.email && <p>{String(errors.email.message)}</p>}
      <button disabled={loading}>
        {loading ? 'Processing' : 'Send'}
      </button>
    </form>
  );
}

Reset-password confirmation form

Once a user reaches the reset route, the job of the UI is to collect the new password, confirm it, and hand off to the reset hook. Server-side token validation still decides whether the action is valid.

Keep password and confirm-password fields together on the same screen.
Disable the submit action while the reset request is in flight.
Return users to login once the password update succeeds.

Reset form example

import React, { useState } from 'react';
import { useResetPassword } from 'albatroz';

export default function ResetPassword() {
  const [password, setPassword] = useState('');
  const [confirmPassword, setConfirmPassword] = useState('');
  const { loading, submit } = useResetPassword();

  const handleSubmit = (event: React.FormEvent) => {
    event.preventDefault();
    submit({ password, confirmPassword });
  };

  return (
    <form onSubmit={handleSubmit}>
      <label htmlFor="password">Password</label>
      <input
        id="password"
        type="password"
        value={password}
        onChange={(event) => setPassword(event.target.value)}
      />

      <label htmlFor="confirmPassword">Confirm password</label>
      <input
        id="confirmPassword"
        type="password"
        value={confirmPassword}
        onChange={(event) => setConfirmPassword(event.target.value)}
      />

      <button disabled={loading}>
        {loading ? 'Processing' : 'Confirm'}
      </button>
    </form>
  );
}

Email template content

The email itself is part of the product experience. It should tell users what happened, why they received the message, and exactly where to click next.

Transactional email component

export type TParams = {
  name: string;
  url: string;
  email: string;
};

const ForgotPasswordEmail = ({ params }: { params: TParams }) => {
  return (
    <div>
      <h2>Password recovery</h2>
      <p>Hello, {params.name}</p>
      <p>
        We received a request to redefine your account password. If you did not
        request this change, you can ignore this email safely.
      </p>
      <a href={params.url}>Redefine password</a>
      <p>If the button does not work, copy the URL into your browser.</p>
      <p>{params.url}</p>
    </div>
  );
};

export default ForgotPasswordEmail;
Keep the wording neutral and security-minded. Do not expose internal implementation details or include unnecessary account data in the email body.

Previous

Auth

Next

API