Basic Change Password
A three-field change-password form - current, new and confirm - with a show/hide toggle and live mismatch feedback.
3 frameworksBeginner
A self-contained card with current/new/confirm fields and a Cancel plus Update button pair.
<form class="w-full max-w-sm rounded-2xl border border-gray-200 bg-white p-6 shadow-sm dark:border-gray-800 dark:bg-gray-950" novalidate>
<h2 class="text-lg font-semibold text-gray-900 dark:text-gray-100">Change password</h2>
<p class="mt-1 text-sm text-gray-500 dark:text-gray-400">Use at least 8 characters with a mix of types.</p>
<div class="mt-5 space-y-4">
<div>
<label for="cp-current" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Current password</label>
<input id="cp-current" name="currentPassword" type="password" autocomplete="current-password"
class="mt-1.5 block w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100 dark:focus-visible:ring-blue-400" />
</div>
<div>
<label for="cp-new" class="block text-sm font-medium text-gray-700 dark:text-gray-300">New password</label>
<input id="cp-new" name="newPassword" type="password" autocomplete="new-password"
class="mt-1.5 block w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100 dark:focus-visible:ring-blue-400" />
</div>
<div>
<label for="cp-confirm" class="block text-sm font-medium text-gray-700 dark:text-gray-300">Confirm new password</label>
<input id="cp-confirm" name="confirmPassword" type="password" autocomplete="new-password"
class="mt-1.5 block w-full rounded-lg border border-gray-300 bg-white px-3 py-2 text-sm text-gray-900 shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-100 dark:focus-visible:ring-blue-400" />
</div>
</div>
<!-- Buttons stack at the narrowest width; two 130px buttons on a 320px phone are two bad targets. -->
<div class="mt-6 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
<button type="button"
class="inline-flex items-center justify-center rounded-lg border border-gray-300 bg-white px-4 py-2.5 text-sm font-semibold text-gray-700 hover:bg-gray-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 dark:border-gray-700 dark:bg-transparent dark:text-gray-200 dark:hover:bg-gray-800">
Cancel
</button>
<button type="submit"
class="inline-flex items-center justify-center rounded-lg bg-blue-600 px-4 py-2.5 text-sm font-semibold text-white hover:bg-blue-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:focus-visible:ring-blue-400 dark:focus-visible:ring-offset-gray-950">
Update password
</button>
</div>
</form>| Prop | Type | Default | Description |
|---|---|---|---|
onSubmit | (values: { currentPassword: string; newPassword: string }) => void | - | Called with the form's values when it is submitted. |
onCancel | () => void | - | On cancel |
className | string | - | Additional classes merged onto the root element. |
The card is `w-full max-w-sm`, so it fills a narrow column and caps on desktop. The action row is `flex-col-reverse` on phones so the primary button sits on top and two buttons never crowd into one bad tap row; both `onSubmit` and `onCancel` default to no-ops.